From 3cc6c798f3d91a6932c8c93e903f8d1d43d62631 Mon Sep 17 00:00:00 2001 From: HelenaIsh <32093844+HelenaIsh@users.noreply.github.com> Date: Mon, 8 Apr 2024 16:46:25 +0500 Subject: [PATCH 001/197] feat(retail-ui): update common dev dependencies (#3398) --- package.json | 12 +- .../docs/Common/SpaceFiller.ts | 4 +- .../ControlsWithValidations.ts | 7 +- packages/react-ui-validations/docs/index.html | 2 +- .../docs/styles/variables.less | 4 +- .../src/Validations/ValidationReader.ts | 5 +- .../components/Preview/Preview.tsx | 5 +- .../components/Button/Button.mixins.ts | 8 +- .../components/Button/Button.styles.ts | 13 +- .../components/Checkbox/Checkbox.styles.ts | 12 +- .../FileUploader/FileUploader.styles.ts | 3 +- .../GlobalLoader/GlobalLoaderView.styles.ts | 12 +- packages/react-ui/components/Input/Input.tsx | 2 +- .../react-ui/components/Loader/Loader.tsx | 2 +- .../components/ResponsiveLayout/types.ts | 3 +- .../ScrollContainer/ScrollContainer.styles.ts | 10 +- .../components/SidePage/SidePage.styles.ts | 4 +- .../SidePage/__stories__/SidePage.stories.tsx | 2 +- .../react-ui/components/Spinner/Spinner.tsx | 2 +- .../Spinner/SpinnerFallbackAnimation.ts | 5 +- .../components/Switcher/Switcher.styles.ts | 4 +- .../components/Textarea/Textarea.styles.ts | 4 +- .../components/Toggle/Toggle.styles.ts | 12 +- .../react-ui/components/Token/Token.styles.ts | 20 +- .../react-ui/internal/ComponentCombinator.tsx | 2 +- .../react-ui/internal/Popup/Popup.styles.ts | 4 +- packages/react-ui/internal/Popup/Popup.tsx | 2 +- .../internal/icons2022/iconConstants.ts | 2 +- packages/react-ui/typings/utility-types.d.ts | 5 +- yarn.lock | 4399 +++++++++-------- 30 files changed, 2559 insertions(+), 2012 deletions(-) diff --git a/package.json b/package.json index 1e658c27d58..201dac84b48 100644 --- a/package.json +++ b/package.json @@ -10,15 +10,15 @@ }, "private": true, "devDependencies": { - "@commitlint/cli": "^12.1.1", - "@commitlint/config-conventional": "^12.1.1", + "@commitlint/cli": "^19.2.1", + "@commitlint/config-conventional": "^19.1.0", "@skbkontur/eslint-config": "*", - "commitizen": "^4.2.3", + "commitizen": "^4.3.0", "cz-conventional-changelog": "^3.3.0", "env-cmd": "^10.1.0", - "husky": "^6.0.0", - "lerna": "^4.0.0", - "prettier": "2.3.2" + "husky": "^9.0.11", + "lerna": "^8.1.2", + "prettier": "3.2.5" }, "scripts": { "commit": "git-cz", diff --git a/packages/react-ui-validations/docs/Common/SpaceFiller.ts b/packages/react-ui-validations/docs/Common/SpaceFiller.ts index 16a3704411a..a4114b6c3a0 100644 --- a/packages/react-ui-validations/docs/Common/SpaceFiller.ts +++ b/packages/react-ui-validations/docs/Common/SpaceFiller.ts @@ -10,7 +10,9 @@ export const SpaceFiller = styled.div` border: 1px solid #dee0e3; display: flex; color: #dee0e3; - text-shadow: 0 0 20px #ffffff, 0 0 20px #ffffff; + text-shadow: + 0 0 20px #ffffff, + 0 0 20px #ffffff; align-items: center; justify-content: center; background: repeating-linear-gradient(45deg, #fafafa, #fafafa 10px, #ffffff 10px, #ffffff 20px); diff --git a/packages/react-ui-validations/docs/Pages/Concepts/InlineValidations/ControlsWithValidations.ts b/packages/react-ui-validations/docs/Pages/Concepts/InlineValidations/ControlsWithValidations.ts index 2783250d2e3..f18fb5eb366 100644 --- a/packages/react-ui-validations/docs/Pages/Concepts/InlineValidations/ControlsWithValidations.ts +++ b/packages/react-ui-validations/docs/Pages/Concepts/InlineValidations/ControlsWithValidations.ts @@ -65,11 +65,8 @@ function prepareProps( }; } -type ExtractProps = TComponentOrTProps extends React.ComponentType - ? P extends { value?: any } - ? P - : never - : never; +type ExtractProps = + TComponentOrTProps extends React.ComponentType ? (P extends { value?: any } ? P : never) : never; type ExtractValue = ExtractProps extends { value?: null | infer TValue } ? TValue : never; diff --git a/packages/react-ui-validations/docs/index.html b/packages/react-ui-validations/docs/index.html index 6a81de0f322..a5a242128bf 100644 --- a/packages/react-ui-validations/docs/index.html +++ b/packages/react-ui-validations/docs/index.html @@ -1,4 +1,4 @@ - + diff --git a/packages/react-ui-validations/docs/styles/variables.less b/packages/react-ui-validations/docs/styles/variables.less index 6a25ce08c29..53cae8c3793 100644 --- a/packages/react-ui-validations/docs/styles/variables.less +++ b/packages/react-ui-validations/docs/styles/variables.less @@ -96,4 +96,6 @@ // ************************ // HEADER // ************************ -@header-box-shadow: 0 1px 8px 0 rgba(0, 0, 0, 0.1), 0 1px 1px 0 rgba(0, 0, 0, 0.08); +@header-box-shadow: + 0 1px 8px 0 rgba(0, 0, 0, 0.1), + 0 1px 1px 0 rgba(0, 0, 0, 0.08); diff --git a/packages/react-ui-validations/src/Validations/ValidationReader.ts b/packages/react-ui-validations/src/Validations/ValidationReader.ts index 226fbd8b871..0d160eccc4f 100644 --- a/packages/react-ui-validations/src/Validations/ValidationReader.ts +++ b/packages/react-ui-validations/src/Validations/ValidationReader.ts @@ -6,7 +6,10 @@ import { ValidationNode } from './Types'; import { LambdaPath, PathTokensCache } from './PathHelper'; export class ValidationReader { - constructor(private readonly node: Nullable>, private readonly tokens: PathTokensCache) {} + constructor( + private readonly node: Nullable>, + private readonly tokens: PathTokensCache, + ) {} public getNode(lambdaPath: LambdaPath): ValidationReader { const path = this.tokens.getOrAdd(lambdaPath); diff --git a/packages/react-ui/.styleguide/components/Preview/Preview.tsx b/packages/react-ui/.styleguide/components/Preview/Preview.tsx index eb094c3c8f8..b24f7c84b2d 100644 --- a/packages/react-ui/.styleguide/components/Preview/Preview.tsx +++ b/packages/react-ui/.styleguide/components/Preview/Preview.tsx @@ -21,8 +21,9 @@ interface PreviewState { error: string | null; } -const withContext = (Wrapped: new (...args: any[]) => React.Component) => (props: PreviewProps) => - {(value: any) => }; +const withContext = (Wrapped: new (...args: any[]) => React.Component) => (props: PreviewProps) => ( + {(value: any) => } +); /** * Измененный компонент Preview, которому был добавлен контекст diff --git a/packages/react-ui/components/Button/Button.mixins.ts b/packages/react-ui/components/Button/Button.mixins.ts index d47cdf0cc66..37739f9793e 100644 --- a/packages/react-ui/components/Button/Button.mixins.ts +++ b/packages/react-ui/components/Button/Button.mixins.ts @@ -146,11 +146,15 @@ export const arrowOutlineMixin = ( return css` .${globalClasses.arrowHelper} { &.${globalClasses.arrowHelperTop} { - box-shadow: inset -${insetWidth} ${insetWidth} 0 0 ${insetColor}, ${outlineWidth} 0 0 0 ${outlineColor} !important; // override :active styles + box-shadow: + inset -${insetWidth} ${insetWidth} 0 0 ${insetColor}, + ${outlineWidth} 0 0 0 ${outlineColor} !important; // override :active styles } &.${globalClasses.arrowHelperBottom} { - box-shadow: inset -${insetWidth} -${insetWidth} 0 0 ${insetColor}, ${outlineWidth} 0 0 0 ${outlineColor} !important; // override :active styles + box-shadow: + inset -${insetWidth} -${insetWidth} 0 0 ${insetColor}, + ${outlineWidth} 0 0 0 ${outlineColor} !important; // override :active styles } // don't hide inner outline diff --git a/packages/react-ui/components/Button/Button.styles.ts b/packages/react-ui/components/Button/Button.styles.ts index cbcbe7e5f2b..413c2a693db 100644 --- a/packages/react-ui/components/Button/Button.styles.ts +++ b/packages/react-ui/components/Button/Button.styles.ts @@ -138,14 +138,17 @@ export const styles = memoizeStyle({ outlineWarning(t: Theme) { return css` - box-shadow: 0 0 0 ${t.btnOutlineWidth} ${t.btnBorderColorWarning}, + box-shadow: + 0 0 0 ${t.btnOutlineWidth} ${t.btnBorderColorWarning}, inset 0 0 0 ${t.btnInsetWidth} ${t.btnInsetColor}; `; }, outlineError(t: Theme) { return css` - box-shadow: 0 0 0 ${t.btnOutlineWidth} ${t.btnBorderColorError}, inset 0 0 0 ${t.btnInsetWidth} ${t.btnInsetColor}; + box-shadow: + 0 0 0 ${t.btnOutlineWidth} ${t.btnBorderColorError}, + inset 0 0 0 ${t.btnInsetWidth} ${t.btnInsetColor}; `; }, @@ -350,7 +353,8 @@ export const styles = memoizeStyle({ &:hover:enabled, &:active:enabled, &:active:hover:enabled { - box-shadow: inset 0 0 0 ${t.btnInsetWidth} ${t.btnOutlineColorFocus}, + box-shadow: + inset 0 0 0 ${t.btnInsetWidth} ${t.btnOutlineColorFocus}, 0 0 0 ${t.btnFocusShadowWidth} ${t.btnBorderColorFocus} !important; // override root:hover style } `; @@ -799,7 +803,8 @@ export const styles = memoizeStyle({ return css` &:hover:enabled, &:hover:active:enabled { - box-shadow: inset 0 0 0 ${t.btnInsetWidth} ${t.btnOutlineColorFocus}, + box-shadow: + inset 0 0 0 ${t.btnInsetWidth} ${t.btnOutlineColorFocus}, 0 0 0 ${t.btnFocusShadowWidth} ${t.btnBorderColorFocus} !important; border-color: ${t.btnBorderColorFocus} !important; } diff --git a/packages/react-ui/components/Checkbox/Checkbox.styles.ts b/packages/react-ui/components/Checkbox/Checkbox.styles.ts index dc165d0bf18..4fd1cef3e1b 100644 --- a/packages/react-ui/components/Checkbox/Checkbox.styles.ts +++ b/packages/react-ui/components/Checkbox/Checkbox.styles.ts @@ -25,7 +25,8 @@ export const styles = memoizeStyle({ } .${globalClasses.box} { - transition: background ${t.transitionDuration} ${t.transitionTimingFunction}, + transition: + background ${t.transitionDuration} ${t.transitionTimingFunction}, box-shadow ${t.transitionDuration} ${t.transitionTimingFunction}; } @@ -180,14 +181,16 @@ export const styles = memoizeStyle({ boxWarning(t: Theme) { return css` - box-shadow: inset 0 0 0 1px ${t.checkboxOutlineColorFocus}, + box-shadow: + inset 0 0 0 1px ${t.checkboxOutlineColorFocus}, 0 0 0 ${t.checkboxOutlineWidth} ${t.checkboxBorderColorWarning} !important; // override hover and active `; }, boxError(t: Theme) { return css` - box-shadow: inset 0 0 0 1px ${t.checkboxOutlineColorFocus}, + box-shadow: + inset 0 0 0 1px ${t.checkboxOutlineColorFocus}, 0 0 0 ${t.checkboxOutlineWidth} ${t.checkboxBorderColorError} !important; // override hover and active `; }, @@ -202,7 +205,8 @@ export const styles = memoizeStyle({ boxFocus(t: Theme) { return css` - box-shadow: inset 0 0 0 1px ${t.checkboxOutlineColorFocus}, + box-shadow: + inset 0 0 0 1px ${t.checkboxOutlineColorFocus}, 0 0 0 ${t.checkboxOutlineWidth} ${t.checkboxBorderColorFocus} !important; // override hover and active `; }, diff --git a/packages/react-ui/components/FileUploader/FileUploader.styles.ts b/packages/react-ui/components/FileUploader/FileUploader.styles.ts index 8084fbaa3c0..936ddcf20d8 100644 --- a/packages/react-ui/components/FileUploader/FileUploader.styles.ts +++ b/packages/react-ui/components/FileUploader/FileUploader.styles.ts @@ -65,7 +65,8 @@ const styles = { outline: none; cursor: pointer; padding: ${t.fileUploaderPaddingY} ${t.fileUploaderPaddingX}; - transition: background-color ${t.transitionDuration} ${t.transitionTimingFunction}, + transition: + background-color ${t.transitionDuration} ${t.transitionTimingFunction}, border-color ${t.transitionDuration} ${t.transitionTimingFunction}; background-color: ${t.fileUploaderUploadButtonBg}; `; diff --git a/packages/react-ui/components/GlobalLoader/GlobalLoaderView.styles.ts b/packages/react-ui/components/GlobalLoader/GlobalLoaderView.styles.ts index 0ed6be4bbe4..d805d27291a 100644 --- a/packages/react-ui/components/GlobalLoader/GlobalLoaderView.styles.ts +++ b/packages/react-ui/components/GlobalLoader/GlobalLoaderView.styles.ts @@ -116,7 +116,8 @@ export const animations = { return css` left: 0; width: 100%; - animation: ${moveToRightAnimation} ${transitionDuration}ms linear, + animation: + ${moveToRightAnimation} ${transitionDuration}ms linear, ${spinnerAnimationDuration}ms ${spinnerAnimation} ${transitionDuration}ms infinite alternate; `; }, @@ -124,7 +125,8 @@ export const animations = { const slowProgressAnimationTime = parseInt(t.globalLoaderSlowAnimationDuration); return css` width: 90%; - animation: ${linearProgressAnimation} ${expectedTime}ms cubic-bezier(0, 0.4, 0.4, 1), + animation: + ${linearProgressAnimation} ${expectedTime}ms cubic-bezier(0, 0.4, 0.4, 1), ${slowProgressAnimationTime}ms ${slowProgressAnimation} ${expectedTime}ms linear; `; }, @@ -133,7 +135,8 @@ export const animations = { const slowProgressAnimationTime = parseInt(t.globalLoaderSlowAnimationDuration); return css` width: 90%; - animation: transitionAnimation ${transitionTime}ms linear, + animation: + transitionAnimation ${transitionTime}ms linear, ${expectedTime}ms acceptAnimation ${transitionTime}ms cubic-bezier(0, 0.4, 0.4, 1), ${slowProgressAnimationTime}ms ${slowProgressAnimation} ${expectedTime + transitionTime}ms linear; @keyframes transitionAnimation { @@ -161,7 +164,8 @@ export const animations = { const slowProgressAnimationTime = parseInt(t.globalLoaderSlowAnimationDuration); return css` width: 90%; - animation: transitionAnimation ${transitionTime}ms linear, + animation: + transitionAnimation ${transitionTime}ms linear, ${slowProgressAnimationTime}ms acceptAnimation ${transitionTime}ms linear; @keyframes transitionAnimation { from { diff --git a/packages/react-ui/components/Input/Input.tsx b/packages/react-ui/components/Input/Input.tsx index 416f85f3b1e..92ac7591e74 100644 --- a/packages/react-ui/components/Input/Input.tsx +++ b/packages/react-ui/components/Input/Input.tsx @@ -32,7 +32,7 @@ export const inputTypes = ['password', 'text', 'number', 'tel', 'search', 'time' */ export type InputSize = SizeProp; export type InputAlign = 'left' | 'center' | 'right'; -export type InputType = typeof inputTypes[number]; +export type InputType = (typeof inputTypes)[number]; export type InputIconType = React.ReactNode | (() => React.ReactNode); export const selectionAllowedTypes: InputType[] = ['text', 'password', 'tel', 'search', 'url']; diff --git a/packages/react-ui/components/Loader/Loader.tsx b/packages/react-ui/components/Loader/Loader.tsx index aedd08c4550..932a91f80c1 100644 --- a/packages/react-ui/components/Loader/Loader.tsx +++ b/packages/react-ui/components/Loader/Loader.tsx @@ -23,7 +23,7 @@ import { styles } from './Loader.styles'; const types = ['mini', 'normal', 'big'] as const; -export type LoaderType = typeof types[number]; +export type LoaderType = (typeof types)[number]; export interface LoaderProps extends CommonProps { children?: React.ReactNode; diff --git a/packages/react-ui/components/ResponsiveLayout/types.ts b/packages/react-ui/components/ResponsiveLayout/types.ts index 0fb73d5e494..85086e681e4 100644 --- a/packages/react-ui/components/ResponsiveLayout/types.ts +++ b/packages/react-ui/components/ResponsiveLayout/types.ts @@ -7,8 +7,7 @@ export interface ResponsiveLayoutOptions { export type ResponsiveLayoutFlags = { [K in keyof T]?: boolean; -} & - ResponsiveLayoutFlagsInternal; +} & ResponsiveLayoutFlagsInternal; export interface ResponsiveLayoutFlagsInternal { isMobile: boolean; diff --git a/packages/react-ui/components/ScrollContainer/ScrollContainer.styles.ts b/packages/react-ui/components/ScrollContainer/ScrollContainer.styles.ts index 6562c9bad06..b813bed8d14 100644 --- a/packages/react-ui/components/ScrollContainer/ScrollContainer.styles.ts +++ b/packages/react-ui/components/ScrollContainer/ScrollContainer.styles.ts @@ -52,14 +52,20 @@ export const styles = memoizeStyle({ border-radius: 5px; background: ${t.scrollContainerScrollBarColor}; opacity: 0; - transition: opacity 0.3s ease-out, width 0.2s, height 0.2s; + transition: + opacity 0.3s ease-out, + width 0.2s, + height 0.2s; `; }, visibleScrollBar() { return css` opacity: 1; - transition: opacity 0.1s ease-out, width 0.2s, height 0.2s; + transition: + opacity 0.1s ease-out, + width 0.2s, + height 0.2s; `; }, diff --git a/packages/react-ui/components/SidePage/SidePage.styles.ts b/packages/react-ui/components/SidePage/SidePage.styles.ts index 354af8c8066..5a37ef30f8a 100644 --- a/packages/react-ui/components/SidePage/SidePage.styles.ts +++ b/packages/react-ui/components/SidePage/SidePage.styles.ts @@ -360,7 +360,9 @@ export const styles = memoizeStyle({ transitionActive() { return css` - transition: transform 0.18s cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.18s cubic-bezier(0.22, 0.61, 0.36, 1); + transition: + transform 0.18s cubic-bezier(0.22, 0.61, 0.36, 1), + opacity 0.18s cubic-bezier(0.22, 0.61, 0.36, 1); opacity: 1 !important; transform: translate(0, 0) !important; `; diff --git a/packages/react-ui/components/SidePage/__stories__/SidePage.stories.tsx b/packages/react-ui/components/SidePage/__stories__/SidePage.stories.tsx index fe09a37c98e..64fc1f4d4d6 100644 --- a/packages/react-ui/components/SidePage/__stories__/SidePage.stories.tsx +++ b/packages/react-ui/components/SidePage/__stories__/SidePage.stories.tsx @@ -265,7 +265,7 @@ class SidePageWithCloseConfiguration extends React.Component { const propertyName = name as keyof SidePageWithCloseConfigurationState; this.setState( (state: SidePageWithCloseConfigurationState) => - ({ [propertyName]: !state[propertyName] } as Shape), + ({ [propertyName]: !state[propertyName] }) as Shape, ); }} ignoreBackgroundClick={this.state.ignoreBackgroundClick} diff --git a/packages/react-ui/components/Spinner/Spinner.tsx b/packages/react-ui/components/Spinner/Spinner.tsx index 57b75d2122e..0918ecd5081 100644 --- a/packages/react-ui/components/Spinner/Spinner.tsx +++ b/packages/react-ui/components/Spinner/Spinner.tsx @@ -20,7 +20,7 @@ import { SpinnerLocale, SpinnerLocaleHelper } from './locale'; const types = ['big', 'mini', 'normal'] as const; -export type SpinnerType = typeof types[number]; +export type SpinnerType = (typeof types)[number]; export interface SpinnerProps extends CommonProps { /** diff --git a/packages/react-ui/components/Spinner/SpinnerFallbackAnimation.ts b/packages/react-ui/components/Spinner/SpinnerFallbackAnimation.ts index 2af917e16fd..6889042b8fa 100644 --- a/packages/react-ui/components/Spinner/SpinnerFallbackAnimation.ts +++ b/packages/react-ui/components/Spinner/SpinnerFallbackAnimation.ts @@ -6,7 +6,10 @@ import { ColorFactory } from '../../lib/styles/ColorFactory'; export class SpinnerFallbackAnimationRunner { private interval: ReturnType | null = null; - constructor(private animations: Animation[], private FPS: number) { + constructor( + private animations: Animation[], + private FPS: number, + ) { this.start(); } diff --git a/packages/react-ui/components/Switcher/Switcher.styles.ts b/packages/react-ui/components/Switcher/Switcher.styles.ts index 96c3210dca4..ca48b2520d7 100644 --- a/packages/react-ui/components/Switcher/Switcher.styles.ts +++ b/packages/react-ui/components/Switcher/Switcher.styles.ts @@ -61,7 +61,9 @@ export const styles = memoizeStyle({ const outsideWidth = `${parseInt(t.switcherOutlineWidth) - insideWidth}px`; return css` border-radius: ${t.switcherBorderRadius}; - box-shadow: inset 0 0 0 ${insideWidth}px ${t.borderColorError}, 0 0 0 ${outsideWidth} ${t.borderColorError}; + box-shadow: + inset 0 0 0 ${insideWidth}px ${t.borderColorError}, + 0 0 0 ${outsideWidth} ${t.borderColorError}; `; }, }); diff --git a/packages/react-ui/components/Textarea/Textarea.styles.ts b/packages/react-ui/components/Textarea/Textarea.styles.ts index 6b4357fca75..1df6868ab75 100644 --- a/packages/react-ui/components/Textarea/Textarea.styles.ts +++ b/packages/react-ui/components/Textarea/Textarea.styles.ts @@ -42,7 +42,9 @@ export const styles = memoizeStyle({ max-width: 100%; min-width: ${t.textareaWidth}; outline: none; - transition: border-color ${t.transitionDuration} ${t.transitionTimingFunction}, height 0.2s ease-out; + transition: + border-color ${t.transitionDuration} ${t.transitionTimingFunction}, + height 0.2s ease-out; vertical-align: middle; width: 100%; border-radius: ${t.textareaBorderRadius}; diff --git a/packages/react-ui/components/Toggle/Toggle.styles.ts b/packages/react-ui/components/Toggle/Toggle.styles.ts index 46cd39e1b97..f8fb95c4c65 100644 --- a/packages/react-ui/components/Toggle/Toggle.styles.ts +++ b/packages/react-ui/components/Toggle/Toggle.styles.ts @@ -296,7 +296,9 @@ export const styles = memoizeStyle({ focused(t: Theme) { return css` - box-shadow: 0 0 0 1px ${t.toggleOutlineColorFocus}, 0 0 0 ${t.toggleOutlineWidth} ${t.toggleFocusShadowColor}; + box-shadow: + 0 0 0 1px ${t.toggleOutlineColorFocus}, + 0 0 0 ${t.toggleOutlineWidth} ${t.toggleFocusShadowColor}; `; }, @@ -327,13 +329,17 @@ export const styles = memoizeStyle({ isWarning(t: Theme) { return css` - box-shadow: 0 0 0 1px ${t.toggleOutlineColorFocus}, 0 0 0 ${t.toggleOutlineWidth} ${t.toggleShadowColorWarning}; + box-shadow: + 0 0 0 1px ${t.toggleOutlineColorFocus}, + 0 0 0 ${t.toggleOutlineWidth} ${t.toggleShadowColorWarning}; `; }, isError(t: Theme) { return css` - box-shadow: 0 0 0 1px ${t.toggleOutlineColorFocus}, 0 0 0 ${t.toggleOutlineWidth} ${t.toggleShadowColorError}; + box-shadow: + 0 0 0 1px ${t.toggleOutlineColorFocus}, + 0 0 0 ${t.toggleOutlineWidth} ${t.toggleShadowColorError}; `; }, diff --git a/packages/react-ui/components/Token/Token.styles.ts b/packages/react-ui/components/Token/Token.styles.ts index 784d121e30e..68af1a97ca3 100644 --- a/packages/react-ui/components/Token/Token.styles.ts +++ b/packages/react-ui/components/Token/Token.styles.ts @@ -243,11 +243,15 @@ export const colorStyles = [ const getVStyle = () => { if (v === 'error') { return css` - box-shadow: 0 0 0 ${t.tokenOutlineWidth} ${t.tokenBorderColorError}, inset 0 0 0 1px ${color(t)}; + box-shadow: + 0 0 0 ${t.tokenOutlineWidth} ${t.tokenBorderColorError}, + inset 0 0 0 1px ${color(t)}; `; } else if (v === 'warning') { return css` - box-shadow: 0 0 0 ${t.tokenOutlineWidth} ${t.tokenBorderColorWarning}, inset 0 0 0 1px ${color(t)}; + box-shadow: + 0 0 0 ${t.tokenOutlineWidth} ${t.tokenBorderColorWarning}, + inset 0 0 0 1px ${color(t)}; `; } @@ -257,7 +261,9 @@ export const colorStyles = [ return css` background-color: ${color(t)}; color: ${ColorFunctions.contrast(color(t))}; - box-shadow: 0 0 0 ${t.tokenBorderWidth} ${ColorFunctions.darken(color(t), '5%')}, inset 0 0 0 1px ${color(t)}; + box-shadow: + 0 0 0 ${t.tokenBorderWidth} ${ColorFunctions.darken(color(t), '5%')}, + inset 0 0 0 1px ${color(t)}; ${getVStyle()} @@ -276,12 +282,16 @@ export const colorStyles = [ }, defaultDisabledWarning(t: Theme) { return css` - box-shadow: 0 0 0 ${t.tokenOutlineWidth} ${t.tokenBorderColorWarning}, inset 0 0 0 1px ${t.tokenDisabledBg}; + box-shadow: + 0 0 0 ${t.tokenOutlineWidth} ${t.tokenBorderColorWarning}, + inset 0 0 0 1px ${t.tokenDisabledBg}; `; }, defaultDisabledError(t: Theme) { return css` - box-shadow: 0 0 0 ${t.tokenOutlineWidth} ${t.tokenBorderColorError}, inset 0 0 0 1px ${t.tokenDisabledBg}; + box-shadow: + 0 0 0 ${t.tokenOutlineWidth} ${t.tokenBorderColorError}, + inset 0 0 0 1px ${t.tokenDisabledBg}; `; }, } as TokenColors, diff --git a/packages/react-ui/internal/ComponentCombinator.tsx b/packages/react-ui/internal/ComponentCombinator.tsx index 382cc03dfca..ee22b30b457 100644 --- a/packages/react-ui/internal/ComponentCombinator.tsx +++ b/packages/react-ui/internal/ComponentCombinator.tsx @@ -40,7 +40,7 @@ export class ComponentCombinator< const pages = []; let row = 0; const sizes = combinations.map((c) => c.length); - const flatCombinations = ([] as typeof combinations[0]).concat(...combinations); + const flatCombinations = ([] as (typeof combinations)[0]).concat(...combinations); for (let j = 0; j < sizes.length - 1; j++) { pages.push({ diff --git a/packages/react-ui/internal/Popup/Popup.styles.ts b/packages/react-ui/internal/Popup/Popup.styles.ts index f93c9c20dcb..415f95b9b9f 100644 --- a/packages/react-ui/internal/Popup/Popup.styles.ts +++ b/packages/react-ui/internal/Popup/Popup.styles.ts @@ -74,7 +74,9 @@ export const styles = memoizeStyle({ }, transitionEnterActive() { return css` - transition: transform 0.18s cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.18s cubic-bezier(0.22, 0.61, 0.36, 1); + transition: + transform 0.18s cubic-bezier(0.22, 0.61, 0.36, 1), + opacity 0.18s cubic-bezier(0.22, 0.61, 0.36, 1); opacity: 1; transform: translate(0, 0); `; diff --git a/packages/react-ui/internal/Popup/Popup.tsx b/packages/react-ui/internal/Popup/Popup.tsx index b77fb3112d3..87f677e3d41 100644 --- a/packages/react-ui/internal/Popup/Popup.tsx +++ b/packages/react-ui/internal/Popup/Popup.tsx @@ -49,7 +49,7 @@ export const PopupPositions = [ ] as const; export const DefaultPosition = PopupPositions[0]; -export type PopupPositionsType = typeof PopupPositions[number]; +export type PopupPositionsType = (typeof PopupPositions)[number]; export const DUMMY_LOCATION: PopupLocation = { position: DefaultPosition, diff --git a/packages/react-ui/internal/icons2022/iconConstants.ts b/packages/react-ui/internal/icons2022/iconConstants.ts index 79d8d9bad27..276f5a69a22 100644 --- a/packages/react-ui/internal/icons2022/iconConstants.ts +++ b/packages/react-ui/internal/icons2022/iconConstants.ts @@ -8,4 +8,4 @@ export type IconSizeAliases = keyof typeof ALIASES_TO_SIZES; export const DEFAULT_ICON_ALIAS: IconSizeAliases = 'small'; -export const DEFAULT_ICON_SIZE: typeof ALIASES_TO_SIZES[IconSizeAliases] = 16; +export const DEFAULT_ICON_SIZE: (typeof ALIASES_TO_SIZES)[IconSizeAliases] = 16; diff --git a/packages/react-ui/typings/utility-types.d.ts b/packages/react-ui/typings/utility-types.d.ts index e57553f4e13..22aa207432a 100644 --- a/packages/react-ui/typings/utility-types.d.ts +++ b/packages/react-ui/typings/utility-types.d.ts @@ -4,8 +4,9 @@ export type Shape = Pick; type ObjectKeyType = string | number | symbol; -export type Diff = ({ [P in T]: P } & - { [P in U]: never } & { [x: string]: never })[T]; +export type Diff = ({ [P in T]: P } & { [P in U]: never } & { + [x: string]: never; +})[T]; export type Override = Pick> & U; diff --git a/yarn.lock b/yarn.lock index 006a4844baf..4e432c31bc6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3624,72 +3624,82 @@ resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== -"@commitlint/cli@^12.1.1": - version "12.1.1" - resolved "https://registry.npmjs.org/@commitlint/cli/-/cli-12.1.1.tgz#740370e557a8a17f415052821cdd5276ecb0ab98" - integrity sha512-SB67/s6VJ50seoPx/Sr2gj1fMzKrx+udgarecGdr8h43ah+M2e22gjQJ7xHv5KwyPQ+6ug1YOMCL34ubT4zupQ== - dependencies: - "@commitlint/format" "^12.1.1" - "@commitlint/lint" "^12.1.1" - "@commitlint/load" "^12.1.1" - "@commitlint/read" "^12.1.1" - "@commitlint/types" "^12.1.1" - get-stdin "8.0.0" - lodash "^4.17.19" - resolve-from "5.0.0" - resolve-global "1.0.0" - yargs "^16.2.0" - -"@commitlint/config-conventional@^12.1.1": - version "12.1.1" - resolved "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-12.1.1.tgz#73dd3b1a7912138420d248f334f15c94c250bc9e" - integrity sha512-15CqbXMsQiEb0qbzjEHe2OkzaXPYSp7RxaS6KoSVk/4W0QiigquavQ+M0huBZze92h0lMS6Pxoq4AJ5CQ3D+iQ== - dependencies: - conventional-changelog-conventionalcommits "^4.3.1" - -"@commitlint/ensure@^12.1.1": - version "12.1.1" - resolved "https://registry.npmjs.org/@commitlint/ensure/-/ensure-12.1.1.tgz#bcefc85f7f8a41bb31f67d7a8966e322b47a6e43" - integrity sha512-XEUQvUjzBVQM7Uv8vYz+c7PDukFvx0AvQEyX/V+PaTkCK/xPvexu7FLbFwvypjSt9BPMf+T/rhB1hVmldkd6lw== - dependencies: - "@commitlint/types" "^12.1.1" - lodash "^4.17.19" +"@commitlint/cli@^19.2.1": + version "19.2.1" + resolved "https://registry.npmjs.org/@commitlint/cli/-/cli-19.2.1.tgz#8f00d27a8b7c7780e75b06fd4658fdc1e9209f1b" + integrity sha512-cbkYUJsLqRomccNxvoJTyv5yn0bSy05BBizVyIcLACkRbVUqYorC351Diw/XFSWC/GtpwiwT2eOvQgFZa374bg== + dependencies: + "@commitlint/format" "^19.0.3" + "@commitlint/lint" "^19.1.0" + "@commitlint/load" "^19.2.0" + "@commitlint/read" "^19.2.1" + "@commitlint/types" "^19.0.3" + execa "^8.0.1" + yargs "^17.0.0" + +"@commitlint/config-conventional@^19.1.0": + version "19.1.0" + resolved "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-19.1.0.tgz#6b4b7938aa3bc308214a683247520f602e55961e" + integrity sha512-KIKD2xrp6Uuk+dcZVj3++MlzIr/Su6zLE8crEDQCZNvWHNQSeeGbzOlNtsR32TUy6H3JbP7nWgduAHCaiGQ6EA== + dependencies: + "@commitlint/types" "^19.0.3" + conventional-changelog-conventionalcommits "^7.0.2" + +"@commitlint/config-validator@^19.0.3": + version "19.0.3" + resolved "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.0.3.tgz#052b181a30da6b4fc16dc5230f4589ac95e0bc81" + integrity sha512-2D3r4PKjoo59zBc2auodrSCaUnCSALCx54yveOFwwP/i2kfEAQrygwOleFWswLqK0UL/F9r07MFi5ev2ohyM4Q== + dependencies: + "@commitlint/types" "^19.0.3" + ajv "^8.11.0" + +"@commitlint/ensure@^19.0.3": + version "19.0.3" + resolved "https://registry.npmjs.org/@commitlint/ensure/-/ensure-19.0.3.tgz#d172b1b72ca88cbd317ea1ee79f3a03dbaccc76e" + integrity sha512-SZEpa/VvBLoT+EFZVb91YWbmaZ/9rPH3ESrINOl0HD2kMYsjvl0tF7nMHh0EpTcv4+gTtZBAe1y/SS6/OhfZzQ== + dependencies: + "@commitlint/types" "^19.0.3" + lodash.camelcase "^4.3.0" + lodash.kebabcase "^4.1.1" + lodash.snakecase "^4.1.1" + lodash.startcase "^4.4.0" + lodash.upperfirst "^4.3.1" "@commitlint/execute-rule@^12.0.1": version "12.0.1" resolved "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-12.0.1.tgz#5bb2eba929270cafb2bd8191799d8b451de7fb7e" integrity sha512-JzyweYfZlFLtXpgP+btzSY3YAkGPg61TqUSYQqBr4+5IaVf1FruMm5v4D5eLu9dAJuNKUfHbM3AEfuEPiZ79pg== -"@commitlint/execute-rule@^12.1.1": - version "12.1.1" - resolved "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-12.1.1.tgz#8aad1d46fb78b3199e4ae36debdc93570bf765ea" - integrity sha512-6mplMGvLCKF5LieL7BRhydpg32tm6LICnWQADrWU4S5g9PKi2utNvhiaiuNPoHUXr29RdbNaGNcyyPv8DSjJsQ== +"@commitlint/execute-rule@^19.0.0": + version "19.0.0" + resolved "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-19.0.0.tgz#928fb239ae8deec82a6e3b05ec9cfe20afa83856" + integrity sha512-mtsdpY1qyWgAO/iOK0L6gSGeR7GFcdW7tIjcNFxcWkfLDF5qVbPHKuGATFqRMsxcO8OUKNj0+3WOHB7EHm4Jdw== -"@commitlint/format@^12.1.1": - version "12.1.1" - resolved "https://registry.npmjs.org/@commitlint/format/-/format-12.1.1.tgz#a6b14f8605171374eecc2c463098d63c127ab7df" - integrity sha512-bTAoOryTFLqls17JTaRwk2WDVOP0NwuG4F/JPK8RaF6DMZNVQTfajkgTxFENNZRnESfau1BvivvEXfUAW2ZsvA== +"@commitlint/format@^19.0.3": + version "19.0.3" + resolved "https://registry.npmjs.org/@commitlint/format/-/format-19.0.3.tgz#6e3dcdc028b39d370ba717b8bde0853705c467dc" + integrity sha512-QjjyGyoiVWzx1f5xOteKHNLFyhyweVifMgopozSgx1fGNrGV8+wp7k6n1t6StHdJ6maQJ+UUtO2TcEiBFRyR6Q== dependencies: - "@commitlint/types" "^12.1.1" - chalk "^4.0.0" + "@commitlint/types" "^19.0.3" + chalk "^5.3.0" -"@commitlint/is-ignored@^12.1.1": - version "12.1.1" - resolved "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-12.1.1.tgz#6075a5cd2dcda7b6ec93322f5dbe2142cfbb3248" - integrity sha512-Sn4fsnWX+wLAJOD/UZeoVruB98te1TyPYRiDEq0MhRJAQIrP+7jE/O3/ass68AAMq00HvH3OK9kt4UBXggcGjA== +"@commitlint/is-ignored@^19.0.3": + version "19.0.3" + resolved "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-19.0.3.tgz#a64e0e217044f2d916127369d21ea12324a834fe" + integrity sha512-MqDrxJaRSVSzCbPsV6iOKG/Lt52Y+PVwFVexqImmYYFhe51iVJjK2hRhOG2jUAGiUHk4jpdFr0cZPzcBkSzXDQ== dependencies: - "@commitlint/types" "^12.1.1" - semver "7.3.5" + "@commitlint/types" "^19.0.3" + semver "^7.6.0" -"@commitlint/lint@^12.1.1": - version "12.1.1" - resolved "https://registry.npmjs.org/@commitlint/lint/-/lint-12.1.1.tgz#cdd898af6eadba8f9e71d7f1255b5a479a757078" - integrity sha512-FFFPpku/E0svL1jaUVqosuZJDDWiNWYBlUw5ZEljh3MwWRcoaWtMIX5bseX+IvHpFZsCTAiBs1kCgNulCi0UvA== +"@commitlint/lint@^19.1.0": + version "19.1.0" + resolved "https://registry.npmjs.org/@commitlint/lint/-/lint-19.1.0.tgz#0f4b26b1452d59a92a28b5fa6de9bdbee18399a1" + integrity sha512-ESjaBmL/9cxm+eePyEr6SFlBUIYlYpI80n+Ltm7IA3MAcrmiP05UMhJdAD66sO8jvo8O4xdGn/1Mt2G5VzfZKw== dependencies: - "@commitlint/is-ignored" "^12.1.1" - "@commitlint/parse" "^12.1.1" - "@commitlint/rules" "^12.1.1" - "@commitlint/types" "^12.1.1" + "@commitlint/is-ignored" "^19.0.3" + "@commitlint/parse" "^19.0.3" + "@commitlint/rules" "^19.0.3" + "@commitlint/types" "^19.0.3" "@commitlint/load@>6.1.1": version "12.0.1" @@ -3704,42 +3714,46 @@ lodash "^4.17.19" resolve-from "^5.0.0" -"@commitlint/load@^12.1.1": - version "12.1.1" - resolved "https://registry.npmjs.org/@commitlint/load/-/load-12.1.1.tgz#5a7fb8be11e520931d1237c5e8dc401b7cc9c6c1" - integrity sha512-qOQtgNdJRULUQWP9jkpTwhj7aEtnqUtqeUpbQ9rjS+GIUST65HZbteNUX4S0mAEGPWqy2aK5xGd73cUfFSvuuw== - dependencies: - "@commitlint/execute-rule" "^12.1.1" - "@commitlint/resolve-extends" "^12.1.1" - "@commitlint/types" "^12.1.1" - chalk "^4.0.0" - cosmiconfig "^7.0.0" - lodash "^4.17.19" - resolve-from "^5.0.0" - -"@commitlint/message@^12.1.1": - version "12.1.1" - resolved "https://registry.npmjs.org/@commitlint/message/-/message-12.1.1.tgz#56eb1dbb561e85e9295380a46ff3b09bc93cac65" - integrity sha512-RakDSLAiOligXjhbLahV8HowF4K75pZIcs0+Ii9Q8Gz5H3DWf1Ngit7alFTWfcbf/+DTjSzVPov5HiwQZPIBUg== - -"@commitlint/parse@^12.1.1": - version "12.1.1" - resolved "https://registry.npmjs.org/@commitlint/parse/-/parse-12.1.1.tgz#3e49d6dc113d59cf266af0db99e320e933108c56" - integrity sha512-nuljIvAbBDr93DgL0wCArftEIhjSghawAwhvrKNV9FFcqAJqfVqitwMxJrNDCQ5pgUMCSKULLOEv+dA0bLlTEQ== - dependencies: - "@commitlint/types" "^12.1.1" - conventional-changelog-angular "^5.0.11" - conventional-commits-parser "^3.0.0" - -"@commitlint/read@^12.1.1": - version "12.1.1" - resolved "https://registry.npmjs.org/@commitlint/read/-/read-12.1.1.tgz#22a2d7fd1eab5e38b9b262311af28ac42f9a5097" - integrity sha512-1k0CQEoZIdixvmqZRKEcWdj2XiKS7SlizEOJ1SE99Qui5d5FlBey8eaooTGgmpR6zObpIHJehtEPzM3VzUT3qA== - dependencies: - "@commitlint/top-level" "^12.1.1" - "@commitlint/types" "^12.1.1" - fs-extra "^9.0.0" - git-raw-commits "^2.0.0" +"@commitlint/load@^19.2.0": + version "19.2.0" + resolved "https://registry.npmjs.org/@commitlint/load/-/load-19.2.0.tgz#3ca51fdead4f1e1e09c9c7df343306412b1ef295" + integrity sha512-XvxxLJTKqZojCxaBQ7u92qQLFMMZc4+p9qrIq/9kJDy8DOrEa7P1yx7Tjdc2u2JxIalqT4KOGraVgCE7eCYJyQ== + dependencies: + "@commitlint/config-validator" "^19.0.3" + "@commitlint/execute-rule" "^19.0.0" + "@commitlint/resolve-extends" "^19.1.0" + "@commitlint/types" "^19.0.3" + chalk "^5.3.0" + cosmiconfig "^9.0.0" + cosmiconfig-typescript-loader "^5.0.0" + lodash.isplainobject "^4.0.6" + lodash.merge "^4.6.2" + lodash.uniq "^4.5.0" + +"@commitlint/message@^19.0.0": + version "19.0.0" + resolved "https://registry.npmjs.org/@commitlint/message/-/message-19.0.0.tgz#f789dd1b7a1f9c784578e0111f46cc3fecf5a531" + integrity sha512-c9czf6lU+9oF9gVVa2lmKaOARJvt4soRsVmbR7Njwp9FpbBgste5i7l/2l5o8MmbwGh4yE1snfnsy2qyA2r/Fw== + +"@commitlint/parse@^19.0.3": + version "19.0.3" + resolved "https://registry.npmjs.org/@commitlint/parse/-/parse-19.0.3.tgz#a2d09876d458e17ad0e1695b04f41af8b50a41c2" + integrity sha512-Il+tNyOb8VDxN3P6XoBBwWJtKKGzHlitEuXA5BP6ir/3loWlsSqDr5aecl6hZcC/spjq4pHqNh0qPlfeWu38QA== + dependencies: + "@commitlint/types" "^19.0.3" + conventional-changelog-angular "^7.0.0" + conventional-commits-parser "^5.0.0" + +"@commitlint/read@^19.2.1": + version "19.2.1" + resolved "https://registry.npmjs.org/@commitlint/read/-/read-19.2.1.tgz#7296b99c9a989e60e5927fff8388a1dd44299c2f" + integrity sha512-qETc4+PL0EUv7Q36lJbPG+NJiBOGg7SSC7B5BsPWOmei+Dyif80ErfWQ0qXoW9oCh7GTpTNRoaVhiI8RbhuaNw== + dependencies: + "@commitlint/top-level" "^19.0.0" + "@commitlint/types" "^19.0.3" + execa "^8.0.1" + git-raw-commits "^4.0.0" + minimist "^1.2.8" "@commitlint/resolve-extends@^12.0.1": version "12.0.1" @@ -3751,37 +3765,40 @@ resolve-from "^5.0.0" resolve-global "^1.0.0" -"@commitlint/resolve-extends@^12.1.1": - version "12.1.1" - resolved "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-12.1.1.tgz#80a78b0940775d17888dd2985b52f93d93e0a885" - integrity sha512-/DXRt0S0U3o9lq5cc8OL1Lkx0IjW0HcDWjUkUXshAajBIKBYSJB8x/loNCi1krNEJ8SwLXUEFt5OLxNO6wE9yQ== +"@commitlint/resolve-extends@^19.1.0": + version "19.1.0" + resolved "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-19.1.0.tgz#fa5b8f921e9c8d76f53624c35bf25b9676bd73fa" + integrity sha512-z2riI+8G3CET5CPgXJPlzftH+RiWYLMYv4C9tSLdLXdr6pBNimSKukYP9MS27ejmscqCTVA4almdLh0ODD2KYg== dependencies: - import-fresh "^3.0.0" - lodash "^4.17.19" + "@commitlint/config-validator" "^19.0.3" + "@commitlint/types" "^19.0.3" + global-directory "^4.0.1" + import-meta-resolve "^4.0.0" + lodash.mergewith "^4.6.2" resolve-from "^5.0.0" - resolve-global "^1.0.0" -"@commitlint/rules@^12.1.1": - version "12.1.1" - resolved "https://registry.npmjs.org/@commitlint/rules/-/rules-12.1.1.tgz#d59182a837d2addf301a3a4ef83316ae7e70248f" - integrity sha512-oCcLF/ykcJfhM2DeeaDyrgdaiuKsqIPNocugdPj2WEyhSYqmx1/u18CV96LAtW+WyyiOLCCeiZwiQutx3T5nXg== +"@commitlint/rules@^19.0.3": + version "19.0.3" + resolved "https://registry.npmjs.org/@commitlint/rules/-/rules-19.0.3.tgz#de647a9055847cae4f3ae32b4798096b604584f3" + integrity sha512-TspKb9VB6svklxNCKKwxhELn7qhtY1rFF8ls58DcFd0F97XoG07xugPjjbVnLqmMkRjZDbDIwBKt9bddOfLaPw== dependencies: - "@commitlint/ensure" "^12.1.1" - "@commitlint/message" "^12.1.1" - "@commitlint/to-lines" "^12.1.1" - "@commitlint/types" "^12.1.1" + "@commitlint/ensure" "^19.0.3" + "@commitlint/message" "^19.0.0" + "@commitlint/to-lines" "^19.0.0" + "@commitlint/types" "^19.0.3" + execa "^8.0.1" -"@commitlint/to-lines@^12.1.1": - version "12.1.1" - resolved "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-12.1.1.tgz#40fbed1767d637249ce49b311a51909d8361ecf8" - integrity sha512-W23AH2XF5rI27MOAPSSr0TUDoRe7ZbFoRtYhFnPu2MBmcuDA9Tmfd9N5sM2tBXtdE26uq3SazwKqGt1OoGAilQ== +"@commitlint/to-lines@^19.0.0": + version "19.0.0" + resolved "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-19.0.0.tgz#aa6618eb371bafbc0cd3b48f0db565c4a40462c6" + integrity sha512-vkxWo+VQU5wFhiP9Ub9Sre0FYe019JxFikrALVoD5UGa8/t3yOJEpEhxC5xKiENKKhUkTpEItMTRAjHw2SCpZw== -"@commitlint/top-level@^12.1.1": - version "12.1.1" - resolved "https://registry.npmjs.org/@commitlint/top-level/-/top-level-12.1.1.tgz#228df8fc36b6d7ea7ad149badfb6ef53dbc7001d" - integrity sha512-g7uRbr81QEIg+pbii0OkE17Zh/2C/f6dSmiMDVRn1S0+hNHR1bENCh18hVUKcV/qKTUsKkFlhhWXM9mQBfxQJw== +"@commitlint/top-level@^19.0.0": + version "19.0.0" + resolved "https://registry.npmjs.org/@commitlint/top-level/-/top-level-19.0.0.tgz#9c44d7cec533bb9598bfae9658737e2d6a903605" + integrity sha512-KKjShd6u1aMGNkCkaX4aG1jOGdn7f8ZI8TR1VEuNqUOjWTOdcDSsmglinglJ18JTjuBX5I1PtjrhQCRcixRVFQ== dependencies: - find-up "^5.0.0" + find-up "^7.0.0" "@commitlint/types@^12.0.1": version "12.0.1" @@ -3790,12 +3807,13 @@ dependencies: chalk "^4.0.0" -"@commitlint/types@^12.1.1": - version "12.1.1" - resolved "https://registry.npmjs.org/@commitlint/types/-/types-12.1.1.tgz#8e651f6af0171cd4f8d464c6c37a7cf63ee071bd" - integrity sha512-+qGH+s2Lo6qwacV2X3/ZypZwaAI84ift+1HBjXdXtI/q0F5NtmXucV3lcQOTviMTNiJhq4qWON2fjci2NItASw== +"@commitlint/types@^19.0.3": + version "19.0.3" + resolved "https://registry.npmjs.org/@commitlint/types/-/types-19.0.3.tgz#feff4ecac2b5c359f2a57f9ab094b2ac80ef0266" + integrity sha512-tpyc+7i6bPG9mvaBbtKUeghfyZSDgWquIDfMgqYtTbmZ9Y9VzEm2je9EYcQ0aoz5o7NvGS+rcDec93yO08MHYA== dependencies: - chalk "^4.0.0" + "@types/conventional-commits-parser" "^5.0.0" + chalk "^5.3.0" "@discoveryjs/json-ext@^0.5.3": version "0.5.7" @@ -4045,6 +4063,23 @@ object-assign "^4.1.1" scheduler "^0.20.1" +"@hutson/parse-repository-url@^3.0.0": + version "3.0.2" + resolved "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" + integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q== + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -4364,6 +4399,13 @@ terminal-link "^2.0.0" v8-to-istanbul "^8.1.0" +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + "@jest/source-map@^24.3.0", "@jest/source-map@^24.9.0": version "24.9.0" resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz#0e263a94430be4b41da683ccc1e6bffe2a191714" @@ -4617,676 +4659,75 @@ dependencies: vary "^1.1.2" -"@lerna/add@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/add/-/add-4.0.0.tgz#c36f57d132502a57b9e7058d1548b7a565ef183f" - integrity sha512-cpmAH1iS3k8JBxNvnMqrGTTjbY/ZAiKa1ChJzFevMYY3eeqbvhsBKnBcxjRXtdrJ6bd3dCQM+ZtK+0i682Fhng== - dependencies: - "@lerna/bootstrap" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/npm-conf" "4.0.0" - "@lerna/validation-error" "4.0.0" - dedent "^0.7.0" - npm-package-arg "^8.1.0" - p-map "^4.0.0" - pacote "^11.2.6" - semver "^7.3.4" - -"@lerna/bootstrap@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/bootstrap/-/bootstrap-4.0.0.tgz#5f5c5e2c6cfc8fcec50cb2fbe569a8c607101891" - integrity sha512-RkS7UbeM2vu+kJnHzxNRCLvoOP9yGNgkzRdy4UV2hNalD7EP41bLvRVOwRYQ7fhc2QcbhnKNdOBihYRL0LcKtw== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/has-npm-version" "4.0.0" - "@lerna/npm-install" "4.0.0" - "@lerna/package-graph" "4.0.0" - "@lerna/pulse-till-done" "4.0.0" - "@lerna/rimraf-dir" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/symlink-binary" "4.0.0" - "@lerna/symlink-dependencies" "4.0.0" - "@lerna/validation-error" "4.0.0" - dedent "^0.7.0" - get-port "^5.1.1" - multimatch "^5.0.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - p-map "^4.0.0" - p-map-series "^2.1.0" - p-waterfall "^2.1.1" - read-package-tree "^5.3.1" - semver "^7.3.4" - -"@lerna/changed@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/changed/-/changed-4.0.0.tgz#b9fc76cea39b9292a6cd263f03eb57af85c9270b" - integrity sha512-cD+KuPRp6qiPOD+BO6S6SN5cARspIaWSOqGBpGnYzLb4uWT8Vk4JzKyYtc8ym1DIwyoFXHosXt8+GDAgR8QrgQ== - dependencies: - "@lerna/collect-updates" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/listable" "4.0.0" - "@lerna/output" "4.0.0" - -"@lerna/check-working-tree@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/check-working-tree/-/check-working-tree-4.0.0.tgz#257e36a602c00142e76082a19358e3e1ae8dbd58" - integrity sha512-/++bxM43jYJCshBiKP5cRlCTwSJdRSxVmcDAXM+1oUewlZJVSVlnks5eO0uLxokVFvLhHlC5kHMc7gbVFPHv6Q== - dependencies: - "@lerna/collect-uncommitted" "4.0.0" - "@lerna/describe-ref" "4.0.0" - "@lerna/validation-error" "4.0.0" - -"@lerna/child-process@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/child-process/-/child-process-4.0.0.tgz#341b96a57dffbd9705646d316e231df6fa4df6e1" - integrity sha512-XtCnmCT9eyVsUUHx6y/CTBYdV9g2Cr/VxyseTWBgfIur92/YKClfEtJTbOh94jRT62hlKLqSvux/UhxXVh613Q== - dependencies: - chalk "^4.1.0" - execa "^5.0.0" - strong-log-transformer "^2.1.0" - -"@lerna/clean@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/clean/-/clean-4.0.0.tgz#8f778b6f2617aa2a936a6b5e085ae62498e57dc5" - integrity sha512-uugG2iN9k45ITx2jtd8nEOoAtca8hNlDCUM0N3lFgU/b1mEQYAPRkqr1qs4FLRl/Y50ZJ41wUz1eazS+d/0osA== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/prompt" "4.0.0" - "@lerna/pulse-till-done" "4.0.0" - "@lerna/rimraf-dir" "4.0.0" - p-map "^4.0.0" - p-map-series "^2.1.0" - p-waterfall "^2.1.1" - -"@lerna/cli@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/cli/-/cli-4.0.0.tgz#8eabd334558836c1664df23f19acb95e98b5bbf3" - integrity sha512-Neaw3GzFrwZiRZv2g7g6NwFjs3er1vhraIniEs0jjVLPMNC4eata0na3GfE5yibkM/9d3gZdmihhZdZ3EBdvYA== - dependencies: - "@lerna/global-options" "4.0.0" - dedent "^0.7.0" - npmlog "^4.1.2" - yargs "^16.2.0" - -"@lerna/collect-uncommitted@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/collect-uncommitted/-/collect-uncommitted-4.0.0.tgz#855cd64612969371cfc2453b90593053ff1ba779" - integrity sha512-ufSTfHZzbx69YNj7KXQ3o66V4RC76ffOjwLX0q/ab//61bObJ41n03SiQEhSlmpP+gmFbTJ3/7pTe04AHX9m/g== - dependencies: - "@lerna/child-process" "4.0.0" - chalk "^4.1.0" - npmlog "^4.1.2" - -"@lerna/collect-updates@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/collect-updates/-/collect-updates-4.0.0.tgz#8e208b1bafd98a372ff1177f7a5e288f6bea8041" - integrity sha512-bnNGpaj4zuxsEkyaCZLka9s7nMs58uZoxrRIPJ+nrmrZYp1V5rrd+7/NYTuunOhY2ug1sTBvTAxj3NZQ+JKnOw== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/describe-ref" "4.0.0" - minimatch "^3.0.4" - npmlog "^4.1.2" - slash "^3.0.0" - -"@lerna/command@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/command/-/command-4.0.0.tgz#991c7971df8f5bf6ae6e42c808869a55361c1b98" - integrity sha512-LM9g3rt5FsPNFqIHUeRwWXLNHJ5NKzOwmVKZ8anSp4e1SPrv2HNc1V02/9QyDDZK/w+5POXH5lxZUI1CHaOK/A== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/package-graph" "4.0.0" - "@lerna/project" "4.0.0" - "@lerna/validation-error" "4.0.0" - "@lerna/write-log-file" "4.0.0" - clone-deep "^4.0.1" - dedent "^0.7.0" - execa "^5.0.0" - is-ci "^2.0.0" - npmlog "^4.1.2" - -"@lerna/conventional-commits@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/conventional-commits/-/conventional-commits-4.0.0.tgz#660fb2c7b718cb942ead70110df61f18c6f99750" - integrity sha512-CSUQRjJHFrH8eBn7+wegZLV3OrNc0Y1FehYfYGhjLE2SIfpCL4bmfu/ViYuHh9YjwHaA+4SX6d3hR+xkeseKmw== - dependencies: - "@lerna/validation-error" "4.0.0" - conventional-changelog-angular "^5.0.12" - conventional-changelog-core "^4.2.2" - conventional-recommended-bump "^6.1.0" - fs-extra "^9.1.0" - get-stream "^6.0.0" - lodash.template "^4.5.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - pify "^5.0.0" - semver "^7.3.4" - -"@lerna/create-symlink@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/create-symlink/-/create-symlink-4.0.0.tgz#8c5317ce5ae89f67825443bd7651bf4121786228" - integrity sha512-I0phtKJJdafUiDwm7BBlEUOtogmu8+taxq6PtIrxZbllV9hWg59qkpuIsiFp+no7nfRVuaasNYHwNUhDAVQBig== - dependencies: - cmd-shim "^4.1.0" - fs-extra "^9.1.0" - npmlog "^4.1.2" - -"@lerna/create@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/create/-/create-4.0.0.tgz#b6947e9b5dfb6530321952998948c3e63d64d730" - integrity sha512-mVOB1niKByEUfxlbKTM1UNECWAjwUdiioIbRQZEeEabtjCL69r9rscIsjlGyhGWCfsdAG5wfq4t47nlDXdLLag== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/npm-conf" "4.0.0" - "@lerna/validation-error" "4.0.0" - dedent "^0.7.0" - fs-extra "^9.1.0" - globby "^11.0.2" - init-package-json "^2.0.2" - npm-package-arg "^8.1.0" +"@lerna/create@8.1.2": + version "8.1.2" + resolved "https://registry.npmjs.org/@lerna/create/-/create-8.1.2.tgz#4dc8b3f59c963275bfb8b390491068751101f477" + integrity sha512-GzScCIkAW3tg3+Yn/MKCH9963bzG+zpjGz2NdfYDlYWI7p0f/SH46v1dqpPpYmZ2E/m3JK8HjTNNNL8eIm8/YQ== + dependencies: + "@npmcli/run-script" "7.0.2" + "@nx/devkit" ">=17.1.2 < 19" + "@octokit/plugin-enterprise-rest" "6.0.1" + "@octokit/rest" "19.0.11" + byte-size "8.1.1" + chalk "4.1.0" + clone-deep "4.0.1" + cmd-shim "6.0.1" + columnify "1.6.0" + conventional-changelog-core "5.0.1" + conventional-recommended-bump "7.0.1" + cosmiconfig "^8.2.0" + dedent "0.7.0" + execa "5.0.0" + fs-extra "^11.1.1" + get-stream "6.0.0" + git-url-parse "13.1.0" + glob-parent "5.1.2" + globby "11.1.0" + graceful-fs "4.2.11" + has-unicode "2.0.1" + ini "^1.3.8" + init-package-json "5.0.0" + inquirer "^8.2.4" + is-ci "3.0.1" + is-stream "2.0.0" + js-yaml "4.1.0" + libnpmpublish "7.3.0" + load-json-file "6.2.0" + lodash "^4.17.21" + make-dir "4.0.0" + minimatch "3.0.5" + multimatch "5.0.0" + node-fetch "2.6.7" + npm-package-arg "8.1.1" + npm-packlist "5.1.1" + npm-registry-fetch "^14.0.5" + npmlog "^6.0.2" + nx ">=17.1.2 < 19" + p-map "4.0.0" + p-map-series "2.1.0" + p-queue "6.6.2" p-reduce "^2.1.0" - pacote "^11.2.6" - pify "^5.0.0" + pacote "^17.0.5" + pify "5.0.0" + read-cmd-shim "4.0.0" + read-package-json "6.0.4" + resolve-from "5.0.0" + rimraf "^4.4.1" semver "^7.3.4" + signal-exit "3.0.7" slash "^3.0.0" + ssri "^9.0.1" + strong-log-transformer "2.1.0" + tar "6.1.11" + temp-dir "1.0.0" + upath "2.0.1" + uuid "^9.0.0" validate-npm-package-license "^3.0.4" - validate-npm-package-name "^3.0.0" - whatwg-url "^8.4.0" - yargs-parser "20.2.4" - -"@lerna/describe-ref@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/describe-ref/-/describe-ref-4.0.0.tgz#53c53b4ea65fdceffa072a62bfebe6772c45d9ec" - integrity sha512-eTU5+xC4C5Gcgz+Ey4Qiw9nV2B4JJbMulsYJMW8QjGcGh8zudib7Sduj6urgZXUYNyhYpRs+teci9M2J8u+UvQ== - dependencies: - "@lerna/child-process" "4.0.0" - npmlog "^4.1.2" - -"@lerna/diff@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/diff/-/diff-4.0.0.tgz#6d3071817aaa4205a07bf77cfc6e932796d48b92" - integrity sha512-jYPKprQVg41+MUMxx6cwtqsNm0Yxx9GDEwdiPLwcUTFx+/qKCEwifKNJ1oGIPBxyEHX2PFCOjkK39lHoj2qiag== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/validation-error" "4.0.0" - npmlog "^4.1.2" - -"@lerna/exec@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/exec/-/exec-4.0.0.tgz#eb6cb95cb92d42590e9e2d628fcaf4719d4a8be6" - integrity sha512-VGXtL/b/JfY84NB98VWZpIExfhLOzy0ozm/0XaS4a2SmkAJc5CeUfrhvHxxkxiTBLkU+iVQUyYEoAT0ulQ8PCw== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/profiler" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/validation-error" "4.0.0" - p-map "^4.0.0" - -"@lerna/filter-options@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/filter-options/-/filter-options-4.0.0.tgz#ac94cc515d7fa3b47e2f7d74deddeabb1de5e9e6" - integrity sha512-vV2ANOeZhOqM0rzXnYcFFCJ/kBWy/3OA58irXih9AMTAlQLymWAK0akWybl++sUJ4HB9Hx12TOqaXbYS2NM5uw== - dependencies: - "@lerna/collect-updates" "4.0.0" - "@lerna/filter-packages" "4.0.0" - dedent "^0.7.0" - npmlog "^4.1.2" - -"@lerna/filter-packages@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/filter-packages/-/filter-packages-4.0.0.tgz#b1f70d70e1de9cdd36a4e50caa0ac501f8d012f2" - integrity sha512-+4AJIkK7iIiOaqCiVTYJxh/I9qikk4XjNQLhE3kixaqgMuHl1NQ99qXRR0OZqAWB9mh8Z1HA9bM5K1HZLBTOqA== - dependencies: - "@lerna/validation-error" "4.0.0" - multimatch "^5.0.0" - npmlog "^4.1.2" - -"@lerna/get-npm-exec-opts@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-4.0.0.tgz#dc955be94a4ae75c374ef9bce91320887d34608f" - integrity sha512-yvmkerU31CTWS2c7DvmAWmZVeclPBqI7gPVr5VATUKNWJ/zmVcU4PqbYoLu92I9Qc4gY1TuUplMNdNuZTSL7IQ== - dependencies: - npmlog "^4.1.2" - -"@lerna/get-packed@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/get-packed/-/get-packed-4.0.0.tgz#0989d61624ac1f97e393bdad2137c49cd7a37823" - integrity sha512-rfWONRsEIGyPJTxFzC8ECb3ZbsDXJbfqWYyeeQQDrJRPnEJErlltRLPLgC2QWbxFgFPsoDLeQmFHJnf0iDfd8w== - dependencies: - fs-extra "^9.1.0" - ssri "^8.0.1" - tar "^6.1.0" - -"@lerna/github-client@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/github-client/-/github-client-4.0.0.tgz#2ced67721363ef70f8e12ffafce4410918f4a8a4" - integrity sha512-2jhsldZtTKXYUBnOm23Lb0Fx8G4qfSXF9y7UpyUgWUj+YZYd+cFxSuorwQIgk5P4XXrtVhsUesIsli+BYSThiw== - dependencies: - "@lerna/child-process" "4.0.0" - "@octokit/plugin-enterprise-rest" "^6.0.1" - "@octokit/rest" "^18.1.0" - git-url-parse "^11.4.4" - npmlog "^4.1.2" - -"@lerna/gitlab-client@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/gitlab-client/-/gitlab-client-4.0.0.tgz#00dad73379c7b38951d4b4ded043504c14e2b67d" - integrity sha512-OMUpGSkeDWFf7BxGHlkbb35T7YHqVFCwBPSIR6wRsszY8PAzCYahtH3IaJzEJyUg6vmZsNl0FSr3pdA2skhxqA== - dependencies: - node-fetch "^2.6.1" - npmlog "^4.1.2" - whatwg-url "^8.4.0" - -"@lerna/global-options@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/global-options/-/global-options-4.0.0.tgz#c7d8b0de6a01d8a845e2621ea89e7f60f18c6a5f" - integrity sha512-TRMR8afAHxuYBHK7F++Ogop2a82xQjoGna1dvPOY6ltj/pEx59pdgcJfYcynYqMkFIk8bhLJJN9/ndIfX29FTQ== - -"@lerna/has-npm-version@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/has-npm-version/-/has-npm-version-4.0.0.tgz#d3fc3292c545eb28bd493b36e6237cf0279f631c" - integrity sha512-LQ3U6XFH8ZmLCsvsgq1zNDqka0Xzjq5ibVN+igAI5ccRWNaUsE/OcmsyMr50xAtNQMYMzmpw5GVLAivT2/YzCg== - dependencies: - "@lerna/child-process" "4.0.0" - semver "^7.3.4" - -"@lerna/import@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/import/-/import-4.0.0.tgz#bde656c4a451fa87ae41733ff8a8da60547c5465" - integrity sha512-FaIhd+4aiBousKNqC7TX1Uhe97eNKf5/SC7c5WZANVWtC7aBWdmswwDt3usrzCNpj6/Wwr9EtEbYROzxKH8ffg== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/prompt" "4.0.0" - "@lerna/pulse-till-done" "4.0.0" - "@lerna/validation-error" "4.0.0" - dedent "^0.7.0" - fs-extra "^9.1.0" - p-map-series "^2.1.0" - -"@lerna/info@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/info/-/info-4.0.0.tgz#b9fb0e479d60efe1623603958a831a88b1d7f1fc" - integrity sha512-8Uboa12kaCSZEn4XRfPz5KU9XXoexSPS4oeYGj76s2UQb1O1GdnEyfjyNWoUl1KlJ2i/8nxUskpXIftoFYH0/Q== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/output" "4.0.0" - envinfo "^7.7.4" - -"@lerna/init@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/init/-/init-4.0.0.tgz#dadff67e6dfb981e8ccbe0e6a310e837962f6c7a" - integrity sha512-wY6kygop0BCXupzWj5eLvTUqdR7vIAm0OgyV9WHpMYQGfs1V22jhztt8mtjCloD/O0nEe4tJhdG62XU5aYmPNQ== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - fs-extra "^9.1.0" - p-map "^4.0.0" - write-json-file "^4.3.0" - -"@lerna/link@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/link/-/link-4.0.0.tgz#c3a38aabd44279d714e90f2451e31b63f0fb65ba" - integrity sha512-KlvPi7XTAcVOByfaLlOeYOfkkDcd+bejpHMCd1KcArcFTwijOwXOVi24DYomIeHvy6HsX/IUquJ4PPUJIeB4+w== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/package-graph" "4.0.0" - "@lerna/symlink-dependencies" "4.0.0" - p-map "^4.0.0" - slash "^3.0.0" - -"@lerna/list@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/list/-/list-4.0.0.tgz#24b4e6995bd73f81c556793fe502b847efd9d1d7" - integrity sha512-L2B5m3P+U4Bif5PultR4TI+KtW+SArwq1i75QZ78mRYxPc0U/piau1DbLOmwrdqr99wzM49t0Dlvl6twd7GHFg== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/listable" "4.0.0" - "@lerna/output" "4.0.0" - -"@lerna/listable@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/listable/-/listable-4.0.0.tgz#d00d6cb4809b403f2b0374fc521a78e318b01214" - integrity sha512-/rPOSDKsOHs5/PBLINZOkRIX1joOXUXEtyUs5DHLM8q6/RP668x/1lFhw6Dx7/U+L0+tbkpGtZ1Yt0LewCLgeQ== - dependencies: - "@lerna/query-graph" "4.0.0" - chalk "^4.1.0" - columnify "^1.5.4" - -"@lerna/log-packed@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/log-packed/-/log-packed-4.0.0.tgz#95168fe2e26ac6a71e42f4be857519b77e57a09f" - integrity sha512-+dpCiWbdzgMAtpajLToy9PO713IHoE6GV/aizXycAyA07QlqnkpaBNZ8DW84gHdM1j79TWockGJo9PybVhrrZQ== - dependencies: - byte-size "^7.0.0" - columnify "^1.5.4" - has-unicode "^2.0.1" - npmlog "^4.1.2" - -"@lerna/npm-conf@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/npm-conf/-/npm-conf-4.0.0.tgz#b259fd1e1cee2bf5402b236e770140ff9ade7fd2" - integrity sha512-uS7H02yQNq3oejgjxAxqq/jhwGEE0W0ntr8vM3EfpCW1F/wZruwQw+7bleJQ9vUBjmdXST//tk8mXzr5+JXCfw== - dependencies: - config-chain "^1.1.12" - pify "^5.0.0" - -"@lerna/npm-dist-tag@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/npm-dist-tag/-/npm-dist-tag-4.0.0.tgz#d1e99b4eccd3414142f0548ad331bf2d53f3257a" - integrity sha512-F20sg28FMYTgXqEQihgoqSfwmq+Id3zT23CnOwD+XQMPSy9IzyLf1fFVH319vXIw6NF6Pgs4JZN2Qty6/CQXGw== - dependencies: - "@lerna/otplease" "4.0.0" - npm-package-arg "^8.1.0" - npm-registry-fetch "^9.0.0" - npmlog "^4.1.2" - -"@lerna/npm-install@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/npm-install/-/npm-install-4.0.0.tgz#31180be3ab3b7d1818a1a0c206aec156b7094c78" - integrity sha512-aKNxq2j3bCH3eXl3Fmu4D54s/YLL9WSwV8W7X2O25r98wzrO38AUN6AB9EtmAx+LV/SP15et7Yueg9vSaanRWg== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/get-npm-exec-opts" "4.0.0" - fs-extra "^9.1.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - signal-exit "^3.0.3" - write-pkg "^4.0.0" - -"@lerna/npm-publish@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/npm-publish/-/npm-publish-4.0.0.tgz#84eb62e876fe949ae1fd62c60804423dbc2c4472" - integrity sha512-vQb7yAPRo5G5r77DRjHITc9piR9gvEKWrmfCH7wkfBnGWEqu7n8/4bFQ7lhnkujvc8RXOsYpvbMQkNfkYibD/w== - dependencies: - "@lerna/otplease" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - fs-extra "^9.1.0" - libnpmpublish "^4.0.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - pify "^5.0.0" - read-package-json "^3.0.0" - -"@lerna/npm-run-script@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/npm-run-script/-/npm-run-script-4.0.0.tgz#dfebf4f4601442e7c0b5214f9fb0d96c9350743b" - integrity sha512-Jmyh9/IwXJjOXqKfIgtxi0bxi1pUeKe5bD3S81tkcy+kyng/GNj9WSqD5ZggoNP2NP//s4CLDAtUYLdP7CU9rA== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/get-npm-exec-opts" "4.0.0" - npmlog "^4.1.2" - -"@lerna/otplease@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/otplease/-/otplease-4.0.0.tgz#84972eb43448f8a1077435ba1c5e59233b725850" - integrity sha512-Sgzbqdk1GH4psNiT6hk+BhjOfIr/5KhGBk86CEfHNJTk9BK4aZYyJD4lpDbDdMjIV4g03G7pYoqHzH765T4fxw== - dependencies: - "@lerna/prompt" "4.0.0" - -"@lerna/output@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/output/-/output-4.0.0.tgz#b1d72215c0e35483e4f3e9994debc82c621851f2" - integrity sha512-Un1sHtO1AD7buDQrpnaYTi2EG6sLF+KOPEAMxeUYG5qG3khTs2Zgzq5WE3dt2N/bKh7naESt20JjIW6tBELP0w== - dependencies: - npmlog "^4.1.2" - -"@lerna/pack-directory@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/pack-directory/-/pack-directory-4.0.0.tgz#8b617db95d20792f043aaaa13a9ccc0e04cb4c74" - integrity sha512-NJrmZNmBHS+5aM+T8N6FVbaKFScVqKlQFJNY2k7nsJ/uklNKsLLl6VhTQBPwMTbf6Tf7l6bcKzpy7aePuq9UiQ== - dependencies: - "@lerna/get-packed" "4.0.0" - "@lerna/package" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - npm-packlist "^2.1.4" - npmlog "^4.1.2" - tar "^6.1.0" - temp-write "^4.0.0" - -"@lerna/package-graph@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/package-graph/-/package-graph-4.0.0.tgz#16a00253a8ac810f72041481cb46bcee8d8123dd" - integrity sha512-QED2ZCTkfXMKFoTGoccwUzjHtZMSf3UKX14A4/kYyBms9xfFsesCZ6SLI5YeySEgcul8iuIWfQFZqRw+Qrjraw== - dependencies: - "@lerna/prerelease-id-from-version" "4.0.0" - "@lerna/validation-error" "4.0.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - semver "^7.3.4" - -"@lerna/package@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/package/-/package-4.0.0.tgz#1b4c259c4bcff45c876ee1d591a043aacbc0d6b7" - integrity sha512-l0M/izok6FlyyitxiQKr+gZLVFnvxRQdNhzmQ6nRnN9dvBJWn+IxxpM+cLqGACatTnyo9LDzNTOj2Db3+s0s8Q== - dependencies: - load-json-file "^6.2.0" - npm-package-arg "^8.1.0" - write-pkg "^4.0.0" - -"@lerna/prerelease-id-from-version@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/prerelease-id-from-version/-/prerelease-id-from-version-4.0.0.tgz#c7e0676fcee1950d85630e108eddecdd5b48c916" - integrity sha512-GQqguzETdsYRxOSmdFZ6zDBXDErIETWOqomLERRY54f4p+tk4aJjoVdd9xKwehC9TBfIFvlRbL1V9uQGHh1opg== - dependencies: - semver "^7.3.4" - -"@lerna/profiler@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/profiler/-/profiler-4.0.0.tgz#8a53ab874522eae15d178402bff90a14071908e9" - integrity sha512-/BaEbqnVh1LgW/+qz8wCuI+obzi5/vRE8nlhjPzdEzdmWmZXuCKyWSEzAyHOJWw1ntwMiww5dZHhFQABuoFz9Q== - dependencies: - fs-extra "^9.1.0" - npmlog "^4.1.2" - upath "^2.0.1" - -"@lerna/project@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/project/-/project-4.0.0.tgz#ff84893935833533a74deff30c0e64ddb7f0ba6b" - integrity sha512-o0MlVbDkD5qRPkFKlBZsXZjoNTWPyuL58564nSfZJ6JYNmgAptnWPB2dQlAc7HWRZkmnC2fCkEdoU+jioPavbg== - dependencies: - "@lerna/package" "4.0.0" - "@lerna/validation-error" "4.0.0" - cosmiconfig "^7.0.0" - dedent "^0.7.0" - dot-prop "^6.0.1" - glob-parent "^5.1.1" - globby "^11.0.2" - load-json-file "^6.2.0" - npmlog "^4.1.2" - p-map "^4.0.0" - resolve-from "^5.0.0" - write-json-file "^4.3.0" - -"@lerna/prompt@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/prompt/-/prompt-4.0.0.tgz#5ec69a803f3f0db0ad9f221dad64664d3daca41b" - integrity sha512-4Ig46oCH1TH5M7YyTt53fT6TuaKMgqUUaqdgxvp6HP6jtdak6+amcsqB8YGz2eQnw/sdxunx84DfI9XpoLj4bQ== - dependencies: - inquirer "^7.3.3" - npmlog "^4.1.2" - -"@lerna/publish@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/publish/-/publish-4.0.0.tgz#f67011305adeba120066a3b6d984a5bb5fceef65" - integrity sha512-K8jpqjHrChH22qtkytA5GRKIVFEtqBF6JWj1I8dWZtHs4Jywn8yB1jQ3BAMLhqmDJjWJtRck0KXhQQKzDK2UPg== - dependencies: - "@lerna/check-working-tree" "4.0.0" - "@lerna/child-process" "4.0.0" - "@lerna/collect-updates" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/describe-ref" "4.0.0" - "@lerna/log-packed" "4.0.0" - "@lerna/npm-conf" "4.0.0" - "@lerna/npm-dist-tag" "4.0.0" - "@lerna/npm-publish" "4.0.0" - "@lerna/otplease" "4.0.0" - "@lerna/output" "4.0.0" - "@lerna/pack-directory" "4.0.0" - "@lerna/prerelease-id-from-version" "4.0.0" - "@lerna/prompt" "4.0.0" - "@lerna/pulse-till-done" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/validation-error" "4.0.0" - "@lerna/version" "4.0.0" - fs-extra "^9.1.0" - libnpmaccess "^4.0.1" - npm-package-arg "^8.1.0" - npm-registry-fetch "^9.0.0" - npmlog "^4.1.2" - p-map "^4.0.0" - p-pipe "^3.1.0" - pacote "^11.2.6" - semver "^7.3.4" - -"@lerna/pulse-till-done@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/pulse-till-done/-/pulse-till-done-4.0.0.tgz#04bace7d483a8205c187b806bcd8be23d7bb80a3" - integrity sha512-Frb4F7QGckaybRhbF7aosLsJ5e9WuH7h0KUkjlzSByVycxY91UZgaEIVjS2oN9wQLrheLMHl6SiFY0/Pvo0Cxg== - dependencies: - npmlog "^4.1.2" - -"@lerna/query-graph@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/query-graph/-/query-graph-4.0.0.tgz#09dd1c819ac5ee3f38db23931143701f8a6eef63" - integrity sha512-YlP6yI3tM4WbBmL9GCmNDoeQyzcyg1e4W96y/PKMZa5GbyUvkS2+Jc2kwPD+5KcXou3wQZxSPzR3Te5OenaDdg== - dependencies: - "@lerna/package-graph" "4.0.0" - -"@lerna/resolve-symlink@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/resolve-symlink/-/resolve-symlink-4.0.0.tgz#6d006628a210c9b821964657a9e20a8c9a115e14" - integrity sha512-RtX8VEUzqT+uLSCohx8zgmjc6zjyRlh6i/helxtZTMmc4+6O4FS9q5LJas2uGO2wKvBlhcD6siibGt7dIC3xZA== - dependencies: - fs-extra "^9.1.0" - npmlog "^4.1.2" - read-cmd-shim "^2.0.0" - -"@lerna/rimraf-dir@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/rimraf-dir/-/rimraf-dir-4.0.0.tgz#2edf3b62d4eb0ef4e44e430f5844667d551ec25a" - integrity sha512-QNH9ABWk9mcMJh2/muD9iYWBk1oQd40y6oH+f3wwmVGKYU5YJD//+zMiBI13jxZRtwBx0vmBZzkBkK1dR11cBg== - dependencies: - "@lerna/child-process" "4.0.0" - npmlog "^4.1.2" - path-exists "^4.0.0" - rimraf "^3.0.2" - -"@lerna/run-lifecycle@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/run-lifecycle/-/run-lifecycle-4.0.0.tgz#e648a46f9210a9bcd7c391df6844498cb5079334" - integrity sha512-IwxxsajjCQQEJAeAaxF8QdEixfI7eLKNm4GHhXHrgBu185JcwScFZrj9Bs+PFKxwb+gNLR4iI5rpUdY8Y0UdGQ== - dependencies: - "@lerna/npm-conf" "4.0.0" - npm-lifecycle "^3.1.5" - npmlog "^4.1.2" - -"@lerna/run-topologically@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/run-topologically/-/run-topologically-4.0.0.tgz#af846eeee1a09b0c2be0d1bfb5ef0f7b04bb1827" - integrity sha512-EVZw9hGwo+5yp+VL94+NXRYisqgAlj0jWKWtAIynDCpghRxCE5GMO3xrQLmQgqkpUl9ZxQFpICgYv5DW4DksQA== - dependencies: - "@lerna/query-graph" "4.0.0" - p-queue "^6.6.2" - -"@lerna/run@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/run/-/run-4.0.0.tgz#4bc7fda055a729487897c23579694f6183c91262" - integrity sha512-9giulCOzlMPzcZS/6Eov6pxE9gNTyaXk0Man+iCIdGJNMrCnW7Dme0Z229WWP/UoxDKg71F2tMsVVGDiRd8fFQ== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/npm-run-script" "4.0.0" - "@lerna/output" "4.0.0" - "@lerna/profiler" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/timer" "4.0.0" - "@lerna/validation-error" "4.0.0" - p-map "^4.0.0" - -"@lerna/symlink-binary@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/symlink-binary/-/symlink-binary-4.0.0.tgz#21009f62d53a425f136cb4c1a32c6b2a0cc02d47" - integrity sha512-zualodWC4q1QQc1pkz969hcFeWXOsVYZC5AWVtAPTDfLl+TwM7eG/O6oP+Rr3fFowspxo6b1TQ6sYfDV6HXNWA== - dependencies: - "@lerna/create-symlink" "4.0.0" - "@lerna/package" "4.0.0" - fs-extra "^9.1.0" - p-map "^4.0.0" - -"@lerna/symlink-dependencies@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/symlink-dependencies/-/symlink-dependencies-4.0.0.tgz#8910eca084ae062642d0490d8972cf2d98e9ebbd" - integrity sha512-BABo0MjeUHNAe2FNGty1eantWp8u83BHSeIMPDxNq0MuW2K3CiQRaeWT3EGPAzXpGt0+hVzBrA6+OT0GPn7Yuw== - dependencies: - "@lerna/create-symlink" "4.0.0" - "@lerna/resolve-symlink" "4.0.0" - "@lerna/symlink-binary" "4.0.0" - fs-extra "^9.1.0" - p-map "^4.0.0" - p-map-series "^2.1.0" - -"@lerna/timer@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/timer/-/timer-4.0.0.tgz#a52e51bfcd39bfd768988049ace7b15c1fd7a6da" - integrity sha512-WFsnlaE7SdOvjuyd05oKt8Leg3ENHICnvX3uYKKdByA+S3g+TCz38JsNs7OUZVt+ba63nC2nbXDlUnuT2Xbsfg== - -"@lerna/validation-error@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/validation-error/-/validation-error-4.0.0.tgz#af9d62fe8304eaa2eb9a6ba1394f9aa807026d35" - integrity sha512-1rBOM5/koiVWlRi3V6dB863E1YzJS8v41UtsHgMr6gB2ncJ2LsQtMKlJpi3voqcgh41H8UsPXR58RrrpPpufyw== - dependencies: - npmlog "^4.1.2" - -"@lerna/version@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/version/-/version-4.0.0.tgz#532659ec6154d8a8789c5ab53878663e244e3228" - integrity sha512-otUgiqs5W9zGWJZSCCMRV/2Zm2A9q9JwSDS7s/tlKq4mWCYriWo7+wsHEA/nPTMDyYyBO5oyZDj+3X50KDUzeA== - dependencies: - "@lerna/check-working-tree" "4.0.0" - "@lerna/child-process" "4.0.0" - "@lerna/collect-updates" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/conventional-commits" "4.0.0" - "@lerna/github-client" "4.0.0" - "@lerna/gitlab-client" "4.0.0" - "@lerna/output" "4.0.0" - "@lerna/prerelease-id-from-version" "4.0.0" - "@lerna/prompt" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/validation-error" "4.0.0" - chalk "^4.1.0" - dedent "^0.7.0" - load-json-file "^6.2.0" - minimatch "^3.0.4" - npmlog "^4.1.2" - p-map "^4.0.0" - p-pipe "^3.1.0" - p-reduce "^2.1.0" - p-waterfall "^2.1.1" - semver "^7.3.4" - slash "^3.0.0" - temp-write "^4.0.0" - write-json-file "^4.3.0" - -"@lerna/write-log-file@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@lerna/write-log-file/-/write-log-file-4.0.0.tgz#18221a38a6a307d6b0a5844dd592ad53fa27091e" - integrity sha512-XRG5BloiArpXRakcnPHmEHJp+4AtnhRtpDIHSghmXD5EichI1uD73J7FgPp30mm2pDRq3FdqB0NbwSEsJ9xFQg== - dependencies: - npmlog "^4.1.2" - write-file-atomic "^3.0.3" + validate-npm-package-name "5.0.0" + write-file-atomic "5.0.1" + write-pkg "4.0.0" + yargs "17.7.2" + yargs-parser "21.1.1" "@mdx-js/loader@^1.6.22": version "1.6.22" @@ -5366,33 +4807,45 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@npmcli/ci-detect@^1.0.0": - version "1.3.0" - resolved "https://registry.npmjs.org/@npmcli/ci-detect/-/ci-detect-1.3.0.tgz#6c1d2c625fb6ef1b9dea85ad0a5afcbef85ef22a" - integrity sha512-oN3y7FAROHhrAt7Rr7PnTSwrHrZVRTS2ZbyxeQwSSYD0ifwM3YNgQqbaRmjcWoPyq77MjchusjJDspbzMmip1Q== +"@npmcli/agent@^2.0.0": + version "2.2.2" + resolved "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz#967604918e62f620a648c7975461c9c9e74fc5d5" + integrity sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og== + dependencies: + agent-base "^7.1.0" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.1" + lru-cache "^10.0.1" + socks-proxy-agent "^8.0.3" -"@npmcli/git@^2.0.1": - version "2.0.6" - resolved "https://registry.npmjs.org/@npmcli/git/-/git-2.0.6.tgz#47b97e96b2eede3f38379262fa3bdfa6eae57bf2" - integrity sha512-a1MnTfeRPBaKbFY07fd+6HugY1WAkKJzdiJvlRub/9o5xz2F/JtPacZZapx5zRJUQFIzSL677vmTSxEcDMrDbg== +"@npmcli/fs@^3.1.0": + version "3.1.0" + resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz#233d43a25a91d68c3a863ba0da6a3f00924a173e" + integrity sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w== dependencies: - "@npmcli/promise-spawn" "^1.1.0" - lru-cache "^6.0.0" - mkdirp "^1.0.3" - npm-pick-manifest "^6.0.0" + semver "^7.3.5" + +"@npmcli/git@^5.0.0": + version "5.0.4" + resolved "https://registry.npmjs.org/@npmcli/git/-/git-5.0.4.tgz#d18c50f99649e6e89e8b427318134f582498700c" + integrity sha512-nr6/WezNzuYUppzXRaYu/W4aT5rLxdXqEFupbh6e/ovlYFQ8hpu1UUPV3Ir/YTl+74iXl2ZOMlGzudh9ZPUchQ== + dependencies: + "@npmcli/promise-spawn" "^7.0.0" + lru-cache "^10.0.1" + npm-pick-manifest "^9.0.0" + proc-log "^3.0.0" promise-inflight "^1.0.1" promise-retry "^2.0.1" - semver "^7.3.2" - unique-filename "^1.1.1" - which "^2.0.2" + semver "^7.3.5" + which "^4.0.0" -"@npmcli/installed-package-contents@^1.0.6": - version "1.0.7" - resolved "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz#ab7408c6147911b970a8abe261ce512232a3f4fa" - integrity sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw== +"@npmcli/installed-package-contents@^2.0.1": + version "2.0.2" + resolved "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz#bfd817eccd9e8df200919e73f57f9e3d9e4f9e33" + integrity sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ== dependencies: - npm-bundled "^1.1.1" - npm-normalize-package-bin "^1.0.1" + npm-bundled "^3.0.0" + npm-normalize-package-bin "^3.0.0" "@npmcli/move-file@^1.0.1": version "1.1.2" @@ -5402,35 +4855,136 @@ mkdirp "^1.0.4" rimraf "^3.0.2" -"@npmcli/node-gyp@^1.0.2": - version "1.0.2" - resolved "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.2.tgz#3cdc1f30e9736dbc417373ed803b42b1a0a29ede" - integrity sha512-yrJUe6reVMpktcvagumoqD9r08fH1iRo01gn1u0zoCApa9lnZGEigVKUd2hzsCId4gdtkZZIVscLhNxMECKgRg== +"@npmcli/node-gyp@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz#101b2d0490ef1aa20ed460e4c0813f0db560545a" + integrity sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA== -"@npmcli/promise-spawn@^1.1.0", "@npmcli/promise-spawn@^1.2.0", "@npmcli/promise-spawn@^1.3.2": - version "1.3.2" - resolved "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz#42d4e56a8e9274fba180dabc0aea6e38f29274f5" - integrity sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg== +"@npmcli/package-json@^5.0.0": + version "5.0.0" + resolved "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.0.0.tgz#77d0f8b17096763ccbd8af03b7117ba6e34d6e91" + integrity sha512-OI2zdYBLhQ7kpNPaJxiflofYIpkNLi+lnGdzqUOfRmCF3r2l1nadcjtCYMJKv/Utm/ZtlffaUuTiAktPHbc17g== + dependencies: + "@npmcli/git" "^5.0.0" + glob "^10.2.2" + hosted-git-info "^7.0.0" + json-parse-even-better-errors "^3.0.0" + normalize-package-data "^6.0.0" + proc-log "^3.0.0" + semver "^7.5.3" + +"@npmcli/promise-spawn@^7.0.0": + version "7.0.1" + resolved "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.1.tgz#a836de2f42a2245d629cf6fbb8dd6c74c74c55af" + integrity sha512-P4KkF9jX3y+7yFUxgcUdDtLy+t4OlDGuEBLNs57AZsfSfg+uV6MLndqGpnl4831ggaEdXwR50XFoZP4VFtHolg== dependencies: - infer-owner "^1.0.4" + which "^4.0.0" -"@npmcli/run-script@^1.8.2": - version "1.8.4" - resolved "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.4.tgz#03ced92503a6fe948cbc0975ce39210bc5e824d6" - integrity sha512-Yd9HXTtF1JGDXZw0+SOn+mWLYS0e7bHBHVC/2C8yqs4wUrs/k8rwBSinD7rfk+3WG/MFGRZKxjyoD34Pch2E/A== - dependencies: - "@npmcli/node-gyp" "^1.0.2" - "@npmcli/promise-spawn" "^1.3.2" - infer-owner "^1.0.4" - node-gyp "^7.1.0" - read-package-json-fast "^2.0.1" +"@npmcli/redact@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@npmcli/redact/-/redact-1.1.0.tgz#78e53a6a34f013543a73827a07ebdc3a6f10454b" + integrity sha512-PfnWuOkQgu7gCbnSsAisaX7hKOdZ4wSAhAzH3/ph5dSGau52kCRrMMGbiSQLwyTZpgldkZ49b0brkOr1AzGBHQ== -"@octokit/auth-token@^2.4.4": - version "2.4.5" - resolved "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz#568ccfb8cb46f36441fac094ce34f7a875b197f3" - integrity sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA== +"@npmcli/run-script@7.0.2": + version "7.0.2" + resolved "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.2.tgz#497e7f058799497889df65900c711312252276d3" + integrity sha512-Omu0rpA8WXvcGeY6DDzyRoY1i5DkCBkzyJ+m2u7PD6quzb0TvSqdIPOkTn8ZBOj7LbbcbMfZ3c5skwSu6m8y2w== dependencies: - "@octokit/types" "^6.0.3" + "@npmcli/node-gyp" "^3.0.0" + "@npmcli/promise-spawn" "^7.0.0" + node-gyp "^10.0.0" + read-package-json-fast "^3.0.0" + which "^4.0.0" + +"@npmcli/run-script@^7.0.0": + version "7.0.4" + resolved "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.4.tgz#9f29aaf4bfcf57f7de2a9e28d1ef091d14b2e6eb" + integrity sha512-9ApYM/3+rBt9V80aYg6tZfzj3UWdiYyCt7gJUD1VJKvWF5nwKDSICXbYIQbspFTq6TOpbsEtIC0LArB8d9PFmg== + dependencies: + "@npmcli/node-gyp" "^3.0.0" + "@npmcli/package-json" "^5.0.0" + "@npmcli/promise-spawn" "^7.0.0" + node-gyp "^10.0.0" + which "^4.0.0" + +"@nrwl/devkit@18.2.3": + version "18.2.3" + resolved "https://registry.npmjs.org/@nrwl/devkit/-/devkit-18.2.3.tgz#4de5589b99c6e5a15da334630079d027a59fdd4c" + integrity sha512-BJQdPmXFze7g4zsHhwSTssAcm/hvl0rXbIzZYQxncsVU4d+Fx0GS3JYBZ+9EcfnCeAEb10jGvn7Rfk+0okMmOw== + dependencies: + "@nx/devkit" "18.2.3" + +"@nrwl/tao@18.2.3": + version "18.2.3" + resolved "https://registry.npmjs.org/@nrwl/tao/-/tao-18.2.3.tgz#c29abf614c23b404d30340326fb52d33822815c0" + integrity sha512-vmteqzGcKPbexaAVPb/7VfXI5dXxzZwSm3rem3z20QlDOmNh1545VLO9YEfT5xzmZT2CC7F0etR4KcrJLtoT5g== + dependencies: + nx "18.2.3" + tslib "^2.3.0" + +"@nx/devkit@18.2.3", "@nx/devkit@>=17.1.2 < 19": + version "18.2.3" + resolved "https://registry.npmjs.org/@nx/devkit/-/devkit-18.2.3.tgz#81788e9d018772414ddad0f1aba7ce007da570a3" + integrity sha512-dugw9Jm3Og28uwGee94P3KYkqiUV7J8RgibOQjQG4J2Vt3DPBNEGSgBD72qKkzpioEo+XSVUkn9h3GrdmnRU+Q== + dependencies: + "@nrwl/devkit" "18.2.3" + ejs "^3.1.7" + enquirer "~2.3.6" + ignore "^5.0.4" + semver "^7.5.3" + tmp "~0.2.1" + tslib "^2.3.0" + yargs-parser "21.1.1" + +"@nx/nx-darwin-arm64@18.2.3": + version "18.2.3" + resolved "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-18.2.3.tgz#4b3f14437e6f5a7233594f63a8d36097e8872af1" + integrity sha512-TEks/vXHE87rNvVqhcIzQOM/+aZvNCf/70PhGG4RBEb+qV0C1kw7nygzdoLI4inFC76Qxhyya/K3J2OnU5ATiw== + +"@nx/nx-darwin-x64@18.2.3": + version "18.2.3" + resolved "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-18.2.3.tgz#bc546836bcce2293181a315666d4a0ea7b42642a" + integrity sha512-UsBbNbNXj+L2OzPyQYotyzmZF4h+ryaZ8quYDfdnlYwvFeqkdb2QJ3vJRd6in0kMWGrdk/ria/wZMCxR7U1ggg== + +"@nx/nx-freebsd-x64@18.2.3": + version "18.2.3" + resolved "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-18.2.3.tgz#afe920b26385fffb77cbad5435ff97607481c01c" + integrity sha512-f9BXGOeRPhrsNm99TCnOqZZeZUqN1BUOEzWa12eo3u+vQG6Qba3qKn7T92SeEzxOx/mUP/Csv3pFYoY6TE26jA== + +"@nx/nx-linux-arm-gnueabihf@18.2.3": + version "18.2.3" + resolved "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-18.2.3.tgz#d438dddcfb0fd255b8903214118c304eb89f33ef" + integrity sha512-ekqr5jZhD6PxGM5IbI/RtlERDJ+8HR04OIdfo6HkbwxwCHxZlzZq+ApEZYum4AbjP6cuc3Zd/us1uuDqfQbeHw== + +"@nx/nx-linux-arm64-gnu@18.2.3": + version "18.2.3" + resolved "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-18.2.3.tgz#a496666a70499d22589dfe0df3d46e738921250b" + integrity sha512-iAW2J8NBFU4zDn5nqRgUq4t7gYC8ALyALzznr97ZvMTQorWfmHYgPUAj/opNqUcr10fjxcmXT0Ux2SX3DgUDmw== + +"@nx/nx-linux-arm64-musl@18.2.3": + version "18.2.3" + resolved "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-18.2.3.tgz#90744f03377959bdc90cf5a8a2f00afb5b084b70" + integrity sha512-AJjGVHGGew0QVKUL30mjFjafowrSDYSQ1GgkJCLuWef5jl4rFvm9ruZswVja1KfZTFaImTCU01tZjPBr3zhmAA== + +"@nx/nx-linux-x64-gnu@18.2.3": + version "18.2.3" + resolved "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-18.2.3.tgz#0c0fac195dcf5eaf58a89bbd4764e06c5e338f14" + integrity sha512-nk5Xg8vmbBRoL0fOgZNBl1paC7hmjACLaSBmU7U2X+Y+QPGQzSw2b+Zn1MKVUWDmc4E6VnQfZ8n0L27+r9NgRw== + +"@nx/nx-linux-x64-musl@18.2.3": + version "18.2.3" + resolved "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-18.2.3.tgz#ba2e290ae3e7e0b43669546591e576c3f7ff2c50" + integrity sha512-bOlhul/eov58k9fX8lltopUDOIBEohZq2qc4ag91W2r4jdp6suAiqfXRxQwNZ2iHd8nAXuCDIHCbUuojs6OZnA== + +"@nx/nx-win32-arm64-msvc@18.2.3": + version "18.2.3" + resolved "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-18.2.3.tgz#5fc56f77ae98e273b1abb9eaf91492f1a40f2dc6" + integrity sha512-olXer0LnCvJrdV5ynd19fZHvvarRK/p1JnkoOUZDPVV+A3jGQQ8+paz+/5iLQBKA+5VcgWyqAaGFJnpyEFmnoQ== + +"@nx/nx-win32-x64-msvc@18.2.3": + version "18.2.3" + resolved "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-18.2.3.tgz#91083c549d4cdbaa0098cf1158edce98f1b440d6" + integrity sha512-BgzPjF/wqi7zIFcspcKzN37BX1wgGo0OTLncK2PN5nyzSQ+XeNbR5laDswxzOGdB4CRLPqak2+YMhYnoiXeRCg== "@octokit/auth-token@^3.0.0": version "3.0.2" @@ -5439,19 +4993,6 @@ dependencies: "@octokit/types" "^8.0.0" -"@octokit/core@^3.2.3": - version "3.4.0" - resolved "https://registry.npmjs.org/@octokit/core/-/core-3.4.0.tgz#b48aa27d755b339fe7550548b340dcc2b513b742" - integrity sha512-6/vlKPP8NF17cgYXqucdshWqmMZGXkuvtcrWCgU5NOI0Pl2GjlmZyWgBMrU8zJ3v2MJlM6++CiB45VKYmhiWWg== - dependencies: - "@octokit/auth-token" "^2.4.4" - "@octokit/graphql" "^4.5.8" - "@octokit/request" "^5.4.12" - "@octokit/request-error" "^2.0.5" - "@octokit/types" "^6.0.3" - before-after-hook "^2.2.0" - universal-user-agent "^6.0.0" - "@octokit/core@^4.0.4": version "4.1.0" resolved "https://registry.npmjs.org/@octokit/core/-/core-4.1.0.tgz#b6b03a478f1716de92b3f4ec4fd64d05ba5a9251" @@ -5465,13 +5006,17 @@ before-after-hook "^2.2.0" universal-user-agent "^6.0.0" -"@octokit/endpoint@^6.0.1": - version "6.0.11" - resolved "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.11.tgz#082adc2aebca6dcefa1fb383f5efb3ed081949d1" - integrity sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ== +"@octokit/core@^4.2.1": + version "4.2.4" + resolved "https://registry.npmjs.org/@octokit/core/-/core-4.2.4.tgz#d8769ec2b43ff37cc3ea89ec4681a20ba58ef907" + integrity sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ== dependencies: - "@octokit/types" "^6.0.3" - is-plain-object "^5.0.0" + "@octokit/auth-token" "^3.0.0" + "@octokit/graphql" "^5.0.0" + "@octokit/request" "^6.0.0" + "@octokit/request-error" "^3.0.0" + "@octokit/types" "^9.0.0" + before-after-hook "^2.2.0" universal-user-agent "^6.0.0" "@octokit/endpoint@^7.0.0": @@ -5483,15 +5028,6 @@ is-plain-object "^5.0.0" universal-user-agent "^6.0.0" -"@octokit/graphql@^4.5.8": - version "4.6.1" - resolved "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.6.1.tgz#f975486a46c94b7dbe58a0ca751935edc7e32cc9" - integrity sha512-2lYlvf4YTDgZCTXTW4+OX+9WTLFtEUc6hGm4qM1nlZjzxj+arizM4aHWzBVBCxY9glh7GIs0WEuiSgbVzv8cmA== - dependencies: - "@octokit/request" "^5.3.0" - "@octokit/types" "^6.0.3" - universal-user-agent "^6.0.0" - "@octokit/graphql@^5.0.0": version "5.0.4" resolved "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.4.tgz#519dd5c05123868276f3ae4e50ad565ed7dff8c8" @@ -5506,49 +5042,35 @@ resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-14.0.0.tgz#949c5019028c93f189abbc2fb42f333290f7134a" integrity sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw== -"@octokit/openapi-types@^5.2.0": - version "5.2.0" - resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-5.2.0.tgz#54e6ca0bc2cd54cd93f0a64658e893c32a5e69ec" - integrity sha512-MInMij2VK5o96Ei6qaHjxBglSZWOXQs9dTZfnGX2Xnr2mhA+yk9L/QCH4RcJGISJJCBclLHuY3ytq+iRgDfX7w== +"@octokit/openapi-types@^18.0.0": + version "18.1.1" + resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-18.1.1.tgz#09bdfdabfd8e16d16324326da5148010d765f009" + integrity sha512-VRaeH8nCDtF5aXWnjPuEMIYf1itK/s3JYyJcWFJT8X9pSNnBtriDf7wlEWsGuhPLl4QIH4xM8fqTXDwJ3Mu6sw== -"@octokit/openapi-types@^6.0.0": - version "6.0.0" - resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-6.0.0.tgz#7da8d7d5a72d3282c1a3ff9f951c8133a707480d" - integrity sha512-CnDdK7ivHkBtJYzWzZm7gEkanA7gKH6a09Eguz7flHw//GacPJLmkHA3f3N++MJmlxD1Fl+mB7B32EEpSCwztQ== - -"@octokit/plugin-enterprise-rest@^6.0.1": +"@octokit/plugin-enterprise-rest@6.0.1": version "6.0.1" resolved "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz#e07896739618dab8da7d4077c658003775f95437" integrity sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw== -"@octokit/plugin-paginate-rest@^2.6.2": - version "2.13.3" - resolved "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.13.3.tgz#f0f1792230805108762d87906fb02d573b9e070a" - integrity sha512-46lptzM9lTeSmIBt/sVP/FLSTPGx6DCzAdSX3PfeJ3mTf4h9sGC26WpaQzMEq/Z44cOcmx8VsOhO+uEgE3cjYg== +"@octokit/plugin-paginate-rest@^6.1.2": + version "6.1.2" + resolved "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.2.tgz#f86456a7a1fe9e58fec6385a85cf1b34072341f8" + integrity sha512-qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ== dependencies: - "@octokit/types" "^6.11.0" + "@octokit/tsconfig" "^1.0.2" + "@octokit/types" "^9.2.3" -"@octokit/plugin-request-log@^1.0.2": - version "1.0.3" - resolved "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.3.tgz#70a62be213e1edc04bb8897ee48c311482f9700d" - integrity sha512-4RFU4li238jMJAzLgAwkBAw+4Loile5haQMQr+uhFq27BmyJXcXSKvoQKqh0agsZEiUlW6iSv3FAgvmGkur7OQ== +"@octokit/plugin-request-log@^1.0.4": + version "1.0.4" + resolved "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85" + integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA== -"@octokit/plugin-rest-endpoint-methods@5.0.0": - version "5.0.0" - resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.0.0.tgz#cf2cdeb24ea829c31688216a5b165010b61f9a98" - integrity sha512-Jc7CLNUueIshXT+HWt6T+M0sySPjF32mSFQAK7UfAg8qGeRI6OM1GSBxDLwbXjkqy2NVdnqCedJcP1nC785JYg== +"@octokit/plugin-rest-endpoint-methods@^7.1.2": + version "7.2.3" + resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.2.3.tgz#37a84b171a6cb6658816c82c4082ac3512021797" + integrity sha512-I5Gml6kTAkzVlN7KCtjOM+Ruwe/rQppp0QU372K1GP7kNOYEKe8Xn5BW4sE62JAHdwpq95OQK/qGNyKQMUzVgA== dependencies: - "@octokit/types" "^6.13.0" - deprecation "^2.3.1" - -"@octokit/request-error@^2.0.0", "@octokit/request-error@^2.0.5": - version "2.0.5" - resolved "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.5.tgz#72cc91edc870281ad583a42619256b380c600143" - integrity sha512-T/2wcCFyM7SkXzNoyVNWjyVlUwBvW3igM3Btr/eKYiPmucXTtkxt2RBsf6gn3LTzaLSLTQtNmvg+dGsOxQrjZg== - dependencies: - "@octokit/types" "^6.0.3" - deprecation "^2.0.0" - once "^1.4.0" + "@octokit/types" "^10.0.0" "@octokit/request-error@^3.0.0": version "3.0.2" @@ -5559,20 +5081,6 @@ deprecation "^2.0.0" once "^1.4.0" -"@octokit/request@^5.3.0", "@octokit/request@^5.4.12": - version "5.4.14" - resolved "https://registry.npmjs.org/@octokit/request/-/request-5.4.14.tgz#ec5f96f78333bb2af390afa5ff66f114b063bc96" - integrity sha512-VkmtacOIQp9daSnBmDI92xNIeLuSRDOIuplp/CJomkvzt7M18NXgG044Cx/LFKLgjKt9T2tZR6AtJayba9GTSA== - dependencies: - "@octokit/endpoint" "^6.0.1" - "@octokit/request-error" "^2.0.0" - "@octokit/types" "^6.7.1" - deprecation "^2.0.0" - is-plain-object "^5.0.0" - node-fetch "^2.6.1" - once "^1.4.0" - universal-user-agent "^6.0.0" - "@octokit/request@^6.0.0": version "6.2.2" resolved "https://registry.npmjs.org/@octokit/request/-/request-6.2.2.tgz#a2ba5ac22bddd5dcb3f539b618faa05115c5a255" @@ -5585,29 +5093,27 @@ node-fetch "^2.6.7" universal-user-agent "^6.0.0" -"@octokit/rest@^18.1.0": - version "18.5.2" - resolved "https://registry.npmjs.org/@octokit/rest/-/rest-18.5.2.tgz#0369e554b7076e3749005147be94c661c7a5a74b" - integrity sha512-Kz03XYfKS0yYdi61BkL9/aJ0pP2A/WK5vF/syhu9/kY30J8He3P68hv9GRpn8bULFx2K0A9MEErn4v3QEdbZcw== +"@octokit/rest@19.0.11": + version "19.0.11" + resolved "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.11.tgz#2ae01634fed4bd1fca5b642767205ed3fd36177c" + integrity sha512-m2a9VhaP5/tUw8FwfnW2ICXlXpLPIqxtg3XcAiGMLj/Xhw3RSBfZ8le/466ktO1Gcjr8oXudGnHhxV1TXJgFxw== dependencies: - "@octokit/core" "^3.2.3" - "@octokit/plugin-paginate-rest" "^2.6.2" - "@octokit/plugin-request-log" "^1.0.2" - "@octokit/plugin-rest-endpoint-methods" "5.0.0" + "@octokit/core" "^4.2.1" + "@octokit/plugin-paginate-rest" "^6.1.2" + "@octokit/plugin-request-log" "^1.0.4" + "@octokit/plugin-rest-endpoint-methods" "^7.1.2" -"@octokit/types@^6.0.3", "@octokit/types@^6.7.1": - version "6.11.0" - resolved "https://registry.npmjs.org/@octokit/types/-/types-6.11.0.tgz#830a608882cde659be19a6e86568abaa619e2ee7" - integrity sha512-RMLAmpPZf/a33EsclBazKg02NCCj4rC69V9sUgf0SuWTjmnBD2QC1nIVtJo7RJrGnwG1+aoFBb2yTrWm/8AS7w== - dependencies: - "@octokit/openapi-types" "^5.2.0" +"@octokit/tsconfig@^1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@octokit/tsconfig/-/tsconfig-1.0.2.tgz#59b024d6f3c0ed82f00d08ead5b3750469125af7" + integrity sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA== -"@octokit/types@^6.11.0", "@octokit/types@^6.13.0": - version "6.13.0" - resolved "https://registry.npmjs.org/@octokit/types/-/types-6.13.0.tgz#779e5b7566c8dde68f2f6273861dd2f0409480d0" - integrity sha512-W2J9qlVIU11jMwKHUp5/rbVUeErqelCsO5vW5PKNb7wAXQVUz87Rc+imjlEvpvbH8yUb+KHmv8NEjVZdsdpyxA== +"@octokit/types@^10.0.0": + version "10.0.0" + resolved "https://registry.npmjs.org/@octokit/types/-/types-10.0.0.tgz#7ee19c464ea4ada306c43f1a45d444000f419a4a" + integrity sha512-Vm8IddVmhCgU1fxC1eyinpwqzXPEYu0NrYzD3YZjlGjyftdLBTeqNblRC0jmJmgxbJIsQlyogVeGnrNaaMVzIg== dependencies: - "@octokit/openapi-types" "^6.0.0" + "@octokit/openapi-types" "^18.0.0" "@octokit/types@^8.0.0": version "8.1.1" @@ -5616,6 +5122,18 @@ dependencies: "@octokit/openapi-types" "^14.0.0" +"@octokit/types@^9.0.0", "@octokit/types@^9.2.3": + version "9.3.2" + resolved "https://registry.npmjs.org/@octokit/types/-/types-9.3.2.tgz#3f5f89903b69f6a2d196d78ec35f888c0013cac5" + integrity sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA== + dependencies: + "@octokit/openapi-types" "^18.0.0" + +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + "@pmmmwh/react-refresh-webpack-plugin@^0.5.1": version "0.5.10" resolved "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz#2eba163b8e7dbabb4ce3609ab5e32ab63dda3ef8" @@ -5713,6 +5231,84 @@ resolved "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== +"@sigstore/bundle@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz#17f8d813b09348b16eeed66a8cf1c3d6bd3d04f1" + integrity sha512-PFutXEy0SmQxYI4texPw3dd2KewuNqv7OuK1ZFtY2fM754yhvG2KdgwIhRnoEE2uHdtdGNQ8s0lb94dW9sELog== + dependencies: + "@sigstore/protobuf-specs" "^0.2.0" + +"@sigstore/bundle@^2.3.0", "@sigstore/bundle@^2.3.1": + version "2.3.1" + resolved "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.1.tgz#f6cdc67c8400e58ca27f0ef495b27a9327512073" + integrity sha512-eqV17lO3EIFqCWK3969Rz+J8MYrRZKw9IBHpSo6DEcEX2c+uzDFOgHE9f2MnyDpfs48LFO4hXmk9KhQ74JzU1g== + dependencies: + "@sigstore/protobuf-specs" "^0.3.1" + +"@sigstore/core@^1.0.0", "@sigstore/core@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@sigstore/core/-/core-1.1.0.tgz#5583d8f7ffe599fa0a89f2bf289301a5af262380" + integrity sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg== + +"@sigstore/protobuf-specs@^0.2.0": + version "0.2.1" + resolved "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz#be9ef4f3c38052c43bd399d3f792c97ff9e2277b" + integrity sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A== + +"@sigstore/protobuf-specs@^0.3.0", "@sigstore/protobuf-specs@^0.3.1": + version "0.3.1" + resolved "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.1.tgz#7095819fa7c5743efde48a858c37b30fab190a09" + integrity sha512-aIL8Z9NsMr3C64jyQzE0XlkEyBLpgEJJFDHLVVStkFV5Q3Il/r/YtY6NJWKQ4cy4AE7spP1IX5Jq7VCAxHHMfQ== + +"@sigstore/sign@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@sigstore/sign/-/sign-1.0.0.tgz#6b08ebc2f6c92aa5acb07a49784cb6738796f7b4" + integrity sha512-INxFVNQteLtcfGmcoldzV6Je0sbbfh9I16DM4yJPw3j5+TFP8X6uIiA18mvpEa9yyeycAKgPmOA3X9hVdVTPUA== + dependencies: + "@sigstore/bundle" "^1.1.0" + "@sigstore/protobuf-specs" "^0.2.0" + make-fetch-happen "^11.0.1" + +"@sigstore/sign@^2.3.0": + version "2.3.0" + resolved "https://registry.npmjs.org/@sigstore/sign/-/sign-2.3.0.tgz#c35e10a3d707e0c69a29bd9f93fa2bdc6275817c" + integrity sha512-tsAyV6FC3R3pHmKS880IXcDJuiFJiKITO1jxR1qbplcsBkZLBmjrEw5GbC7ikD6f5RU1hr7WnmxB/2kKc1qUWQ== + dependencies: + "@sigstore/bundle" "^2.3.0" + "@sigstore/core" "^1.0.0" + "@sigstore/protobuf-specs" "^0.3.1" + make-fetch-happen "^13.0.0" + +"@sigstore/tuf@^1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.3.tgz#2a65986772ede996485728f027b0514c0b70b160" + integrity sha512-2bRovzs0nJZFlCN3rXirE4gwxCn97JNjMmwpecqlbgV9WcxX7WRuIrgzx/X7Ib7MYRbyUTpBYE0s2x6AmZXnlg== + dependencies: + "@sigstore/protobuf-specs" "^0.2.0" + tuf-js "^1.1.7" + +"@sigstore/tuf@^2.3.1": + version "2.3.2" + resolved "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.2.tgz#e9c5bffc2a5f3434f87195902d7f9cd7f48c70fa" + integrity sha512-mwbY1VrEGU4CO55t+Kl6I7WZzIl+ysSzEYdA1Nv/FTrl2bkeaPXo5PnWZAVfcY2zSdhOpsUTJW67/M2zHXGn5w== + dependencies: + "@sigstore/protobuf-specs" "^0.3.0" + tuf-js "^2.2.0" + +"@sigstore/verify@^1.2.0": + version "1.2.0" + resolved "https://registry.npmjs.org/@sigstore/verify/-/verify-1.2.0.tgz#48549186305d8a5e471a3a304cf4cb3e0c99dde7" + integrity sha512-hQF60nc9yab+Csi4AyoAmilGNfpXT+EXdBgFkP9OgPwIBPwyqVf7JAWPtmqrrrneTmAT6ojv7OlH1f6Ix5BG4Q== + dependencies: + "@sigstore/bundle" "^2.3.1" + "@sigstore/core" "^1.1.0" + "@sigstore/protobuf-specs" "^0.3.1" + +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + "@sinonjs/commons@^1.7.0": version "1.8.2" resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz#858f5c4b48d80778fde4b9d541f27edc0d56488b" @@ -6899,6 +6495,32 @@ "@types/semver" "^7.3.9" ts-type "^2.1.2" +"@tufjs/canonical-json@1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz#eade9fd1f537993bc1f0949f3aea276ecc4fab31" + integrity sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ== + +"@tufjs/canonical-json@2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz#a52f61a3d7374833fca945b2549bc30a2dd40d0a" + integrity sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA== + +"@tufjs/models@1.0.4": + version "1.0.4" + resolved "https://registry.npmjs.org/@tufjs/models/-/models-1.0.4.tgz#5a689630f6b9dbda338d4b208019336562f176ef" + integrity sha512-qaGV9ltJP0EO25YfFUPhxRVK0evXFIAGicsVXuRim4Ed9cjPxYhNnNJ49SFmbeLgtxpslIkX317IgpfcHPVj/A== + dependencies: + "@tufjs/canonical-json" "1.0.0" + minimatch "^9.0.0" + +"@tufjs/models@2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@tufjs/models/-/models-2.0.0.tgz#c7ab241cf11dd29deb213d6817dabb8c99ce0863" + integrity sha512-c8nj8BaOExmZKO2DXhDfegyhSGcG9E/mPN3U13L+/PsoWm1uaGiHHjxqSHQiasDBQwDA3aHuw9+9spYAP1qvvg== + dependencies: + "@tufjs/canonical-json" "2.0.0" + minimatch "^9.0.3" + "@types/anymatch@*": version "1.3.1" resolved "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" @@ -6982,6 +6604,13 @@ resolved "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== +"@types/conventional-commits-parser@^5.0.0": + version "5.0.0" + resolved "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz#8c9d23e0b415b24b91626d07017303755d542dc8" + integrity sha512-loB369iXNmAZglwWATL+WRe+CRMmmBPtpolYzIebFaX4YA3x+BEfLqhUAV9WanycKI3TG1IMr5bMJDajDKLlUQ== + dependencies: + "@types/node" "*" + "@types/detect-indent@0.1.30": version "0.1.30" resolved "https://registry.npmjs.org/@types/detect-indent/-/detect-indent-0.1.30.tgz#dc682bb412b4e65ba098e70edad73b4833fb910d" @@ -7955,12 +7584,32 @@ tslib "^2.3.1" upath2 "^3.1.10" +"@yarnpkg/lockfile@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== + +"@yarnpkg/parsers@3.0.0-rc.46": + version "3.0.0-rc.46" + resolved "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.0-rc.46.tgz#03f8363111efc0ea670e53b0282cd3ef62de4e01" + integrity sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q== + dependencies: + js-yaml "^3.10.0" + tslib "^2.4.0" + "@zeit/schemas@2.6.0": version "2.6.0" resolved "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.6.0.tgz#004e8e553b4cd53d538bd38eac7bcbf58a867fe3" integrity sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg== -JSONStream@^1.0.4: +"@zkochan/js-yaml@0.0.6": + version "0.0.6" + resolved "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.6.tgz#975f0b306e705e28b8068a07737fa46d3fc04826" + integrity sha512-nzvgl3VfhcELQ8LyVrYOru+UtAy1nrygk2+AGbTm8a5YcO6o8lSjAT+pfg3vJWxIoZKOUhrK6UU7xW/+00kQrg== + dependencies: + argparse "^2.0.1" + +JSONStream@^1.3.5: version "1.3.5" resolved "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== @@ -7983,6 +7632,11 @@ abbrev@1: resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +abbrev@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" + integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== + accepts@^1.3.5, accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" @@ -8080,20 +7734,25 @@ agent-base@5: resolved "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c" integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g== -agent-base@6: +agent-base@6, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== dependencies: debug "4" -agentkeepalive@^4.1.3: - version "4.1.4" - resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.1.4.tgz#d928028a4862cb11718e55227872e842a44c945b" - integrity sha512-+V/rGa3EuU74H6wR04plBb7Ks10FbtUQgRj/FQOG7uUIEuaINI+AiqJR1k6t3SVNs7o7ZjIdus6706qqzVq8jQ== +agent-base@^7.0.2, agent-base@^7.1.0, agent-base@^7.1.1: + version "7.1.1" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" + integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== + dependencies: + debug "^4.3.4" + +agentkeepalive@^4.2.1: + version "4.5.0" + resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" + integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== dependencies: - debug "^4.1.0" - depd "^1.1.2" humanize-ms "^1.2.1" aggregate-error@^3.0.0: @@ -8181,7 +7840,7 @@ ajv@^7.0.2: require-from-string "^2.0.2" uri-js "^4.2.2" -ajv@^8.0.0, ajv@^8.8.0: +ajv@^8.0.0, ajv@^8.11.0, ajv@^8.8.0: version "8.12.0" resolved "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== @@ -8267,6 +7926,11 @@ ansi-regex@^5.0.0, ansi-regex@^5.0.1: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -8286,6 +7950,11 @@ ansi-styles@^5.0.0: resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + ansi-to-html@^0.6.11: version "0.6.14" resolved "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.6.14.tgz#65fe6d08bba5dd9db33f44a20aec331e0010dad8" @@ -8330,16 +7999,16 @@ app-root-dir@^1.0.2: resolved "https://registry.npmjs.org/app-root-dir/-/app-root-dir-1.0.2.tgz#38187ec2dea7577fff033ffcb12172692ff6e118" integrity sha1-OBh+wt6nV3//Az/8sSFyaS/24Rg= -aproba@^1.0.3, aproba@^1.1.1: - version "1.2.0" - resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== - -"aproba@^1.0.3 || ^2.0.0", aproba@^2.0.0: +"aproba@^1.0.3 || ^2.0.0": version "2.0.0" resolved "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== +aproba@^1.1.1: + version "1.2.0" + resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + arch@^2.1.0, arch@^2.1.1: version "2.2.0" resolved "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" @@ -8353,13 +8022,13 @@ are-we-there-yet@^2.0.0: delegates "^1.0.0" readable-stream "^3.6.0" -are-we-there-yet@~1.1.2: - version "1.1.5" - resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== +are-we-there-yet@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd" + integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg== dependencies: delegates "^1.0.0" - readable-stream "^2.0.6" + readable-stream "^3.6.0" arg@2.0.0: version "2.0.0" @@ -8421,11 +8090,6 @@ array-filter@^1.0.0: resolved "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83" integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM= -array-find-index@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" - integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= - array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -8514,11 +8178,6 @@ arrify@^2.0.1: resolved "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== -asap@^2.0.0: - version "2.0.6" - resolved "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= - asn1.js@^5.2.0: version "5.4.1" resolved "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" @@ -8632,6 +8291,11 @@ async@^2.6.1, async@^2.6.2: dependencies: lodash "^4.17.14" +async@^3.2.3: + version "3.2.5" + resolved "https://registry.npmjs.org/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" + integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -8704,6 +8368,15 @@ axios@^0.24.0: dependencies: follow-redirects "^1.14.4" +axios@^1.6.0: + version "1.6.8" + resolved "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66" + integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + axobject-query@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" @@ -9505,15 +9178,17 @@ builtins@^1.0.3: resolved "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= -byline@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" - integrity sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE= +builtins@^5.0.0: + version "5.1.0" + resolved "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz#6d85eeb360c4ebc166c3fdef922a15aa7316a5e8" + integrity sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg== + dependencies: + semver "^7.0.0" -byte-size@^7.0.0: - version "7.0.1" - resolved "https://registry.npmjs.org/byte-size/-/byte-size-7.0.1.tgz#b1daf3386de7ab9d706b941a748dbfc71130dee3" - integrity sha512-crQdqyCwhokxwV1UyDzLZanhkugAgft7vt0qbbdt60C6Zf3CAiGmtUCylbtYwrU6loOUw3euGrNtW1J651ot1A== +byte-size@8.1.1: + version "8.1.1" + resolved "https://registry.npmjs.org/byte-size/-/byte-size-8.1.1.tgz#3424608c62d59de5bfda05d31e0313c6174842ae" + integrity sha512-tUkzZWK0M/qdoLEqikxBWe4kumyuwjl3HO6zHTr4yEI23EojPtLYXdG1+AQY7MN0cGyNDvEaJ8wiYQm6P2bPxg== bytes@3.0.0: version "3.0.0" @@ -9569,6 +9244,42 @@ cacache@^15.0.5: tar "^6.0.2" unique-filename "^1.1.1" +cacache@^17.0.0: + version "17.1.4" + resolved "https://registry.npmjs.org/cacache/-/cacache-17.1.4.tgz#b3ff381580b47e85c6e64f801101508e26604b35" + integrity sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A== + dependencies: + "@npmcli/fs" "^3.1.0" + fs-minipass "^3.0.0" + glob "^10.2.2" + lru-cache "^7.7.1" + minipass "^7.0.3" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + p-map "^4.0.0" + ssri "^10.0.0" + tar "^6.1.11" + unique-filename "^3.0.0" + +cacache@^18.0.0: + version "18.0.2" + resolved "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz#fd527ea0f03a603be5c0da5805635f8eef00c60c" + integrity sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw== + dependencies: + "@npmcli/fs" "^3.1.0" + fs-minipass "^3.0.0" + glob "^10.2.2" + lru-cache "^10.0.1" + minipass "^7.0.3" + minipass-collect "^2.0.1" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + p-map "^4.0.0" + ssri "^10.0.0" + tar "^6.1.11" + unique-filename "^3.0.0" + cache-base@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -9597,6 +9308,11 @@ cachedir@2.2.0: resolved "https://registry.npmjs.org/cachedir/-/cachedir-2.2.0.tgz#19afa4305e05d79e417566882e0c8f960f62ff0e" integrity sha512-VvxA0xhNqIIfg0V9AmJkDg91DaJwryutH5rVEZAhcNi4iJFj9f+QxmAjgK1LT9I8OgToX27fypX6/MeCXVbBjQ== +cachedir@2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz#0c75892a052198f0b21c7c1804d8331edfcae0e8" + integrity sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw== + call-bind@^1.0.0, call-bind@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" @@ -9628,14 +9344,6 @@ camelcase-css@2.0.1: resolved "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== -camelcase-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" - integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= - dependencies: - camelcase "^2.0.0" - map-obj "^1.0.0" - camelcase-keys@^6.2.2: version "6.2.2" resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" @@ -9645,11 +9353,6 @@ camelcase-keys@^6.2.2: map-obj "^4.0.0" quick-lru "^4.0.1" -camelcase@^2.0.0: - version "2.1.1" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" - integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= - camelcase@^4.0.0: version "4.1.0" resolved "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" @@ -9769,7 +9472,7 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.1.2: +chalk@^4.0.2, chalk@^4.1.1, chalk@^4.1.2: version "4.1.2" resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -9777,6 +9480,11 @@ chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^5.3.0: + version "5.3.0" + resolved "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -9880,7 +9588,7 @@ chokidar@^3.4.1, chokidar@^3.4.2: optionalDependencies: fsevents "~2.3.1" -chownr@^1.1.1, chownr@^1.1.4: +chownr@^1.1.1: version "1.1.4" resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== @@ -9907,6 +9615,11 @@ ci-info@^3.2.0: resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== +ci-info@^3.6.1: + version "3.9.0" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -9965,6 +9678,13 @@ cli-boxes@^2.2.1: resolved "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== +cli-cursor@3.1.0, cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" @@ -9972,12 +9692,10 @@ cli-cursor@^2.1.0: dependencies: restore-cursor "^2.0.0" -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" +cli-spinners@2.6.1: + version "2.6.1" + resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" + integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== cli-spinners@^2.2.0: version "2.5.0" @@ -10075,7 +9793,16 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" -clone-deep@^4.0.1: +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +clone-deep@4.0.1, clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== @@ -10101,12 +9828,10 @@ clsx@^1.0.4: resolved "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== -cmd-shim@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/cmd-shim/-/cmd-shim-4.1.0.tgz#b3a904a6743e9fede4148c6f3800bf2a08135bdd" - integrity sha512-lb9L7EM4I/ZRVuljLPEtUJOP+xiQVknZ4ZMpMgEp4JzNldPb27HU03hi6K1/6CoIuit/Zm/LQXySErFeXxDprw== - dependencies: - mkdirp-infer-owner "^2.0.0" +cmd-shim@6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/cmd-shim/-/cmd-shim-6.0.1.tgz#a65878080548e1dca760b3aea1e21ed05194da9d" + integrity sha512-S9iI9y0nKR4hwEQsVWpyxld/6kRfGepGfzff83FcaiEBpmvlbA2nnGe7Cylgrx2f/p1P5S5wpRm9oL8z1PbS3Q== co-body@^6.0.0: version "6.1.0" @@ -10170,7 +9895,7 @@ color-name@~1.1.4: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-support@^1.1.2: +color-support@^1.1.2, color-support@^1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== @@ -10195,12 +9920,12 @@ colors@~0.6.0-1: resolved "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" integrity sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w= -columnify@^1.5.4: - version "1.5.4" - resolved "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" - integrity sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs= +columnify@1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz#6989531713c9008bb29735e61e37acf5bd553cf3" + integrity sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q== dependencies: - strip-ansi "^3.0.0" + strip-ansi "^6.0.1" wcwidth "^1.0.0" combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: @@ -10235,7 +9960,7 @@ commander@~2.1.0: resolved "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" integrity sha1-0SG7roYNmZKj1Re6lvVliOR8Z4E= -commitizen@^4.0.3, commitizen@^4.2.3: +commitizen@^4.0.3: version "4.2.3" resolved "https://registry.npmjs.org/commitizen/-/commitizen-4.2.3.tgz#088d0ef72500240d331b11e02e288223667c1475" integrity sha512-pYlYEng7XMV2TW4xtjDKBGqeJ0Teq2zyRSx2S3Ml1XAplHSlJZK8vm1KdGclpMEZuGafbS5TeHXIVnHk8RWIzQ== @@ -10255,6 +9980,26 @@ commitizen@^4.0.3, commitizen@^4.2.3: strip-bom "4.0.0" strip-json-comments "3.0.1" +commitizen@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/commitizen/-/commitizen-4.3.0.tgz#0d056c542a2d2b1f9b9aba981aa32575b2849924" + integrity sha512-H0iNtClNEhT0fotHvGV3E9tDejDeS04sN1veIebsKYGMuGscFaswRoYJKmT3eW85eIJAs0F28bG2+a/9wCOfPw== + dependencies: + cachedir "2.3.0" + cz-conventional-changelog "3.3.0" + dedent "0.7.0" + detect-indent "6.1.0" + find-node-modules "^2.1.2" + find-root "1.1.0" + fs-extra "9.1.0" + glob "7.2.3" + inquirer "8.2.5" + is-utf8 "^0.2.1" + lodash "4.17.21" + minimist "1.2.7" + strip-bom "4.0.0" + strip-json-comments "3.1.1" + common-dir@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/common-dir/-/common-dir-3.0.0.tgz#37d92f4eb998ec95f67216f1a2059f40aae71736" @@ -10358,14 +10103,6 @@ concat-stream@^2.0.0: readable-stream "^3.0.2" typedarray "^0.0.6" -config-chain@^1.1.12: - version "1.1.12" - resolved "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" - integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== - dependencies: - ini "^1.3.4" - proto-list "~1.2.1" - connect-history-api-fallback@^1.6.0: version "1.6.0" resolved "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" @@ -10376,7 +10113,7 @@ console-browserify@^1.1.0: resolved "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== -console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: +console-control-strings@^1.0.0, console-control-strings@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= @@ -10408,104 +10145,100 @@ content-type@^1.0.4, content-type@~1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== -conventional-changelog-angular@^5.0.11, conventional-changelog-angular@^5.0.12: - version "5.0.12" - resolved "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.12.tgz#c979b8b921cbfe26402eb3da5bbfda02d865a2b9" - integrity sha512-5GLsbnkR/7A89RyHLvvoExbiGbd9xKdKqDTrArnPbOqBqG/2wIosu0fHwpeIRI8Tl94MhVNBXcLJZl92ZQ5USw== +conventional-changelog-angular@7.0.0, conventional-changelog-angular@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz#5eec8edbff15aa9b1680a8dcfbd53e2d7eb2ba7a" + integrity sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ== dependencies: compare-func "^2.0.0" - q "^1.5.1" -conventional-changelog-conventionalcommits@^4.3.1: - version "4.5.0" - resolved "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.5.0.tgz#a02e0b06d11d342fdc0f00c91d78265ed0bc0a62" - integrity sha512-buge9xDvjjOxJlyxUnar/+6i/aVEVGA7EEh4OafBCXPlLUQPGbRUBhBUveWRxzvR8TEjhKEP4BdepnpG2FSZXw== +conventional-changelog-conventionalcommits@^7.0.2: + version "7.0.2" + resolved "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz#aa5da0f1b2543094889e8cf7616ebe1a8f5c70d5" + integrity sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w== dependencies: compare-func "^2.0.0" - lodash "^4.17.15" - q "^1.5.1" -conventional-changelog-core@^4.2.2: - version "4.2.2" - resolved "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.2.tgz#f0897df6d53b5d63dec36b9442bd45354f8b3ce5" - integrity sha512-7pDpRUiobQDNkwHyJG7k9f6maPo9tfPzkSWbRq97GGiZqisElhnvUZSvyQH20ogfOjntB5aadvv6NNcKL1sReg== +conventional-changelog-core@5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-5.0.1.tgz#3c331b155d5b9850f47b4760aeddfc983a92ad49" + integrity sha512-Rvi5pH+LvgsqGwZPZ3Cq/tz4ty7mjijhr3qR4m9IBXNbxGGYgTVVO+duXzz9aArmHxFtwZ+LRkrNIMDQzgoY4A== dependencies: add-stream "^1.0.0" - conventional-changelog-writer "^4.0.18" - conventional-commits-parser "^3.2.0" - dateformat "^3.0.0" - get-pkg-repo "^1.0.0" - git-raw-commits "^2.0.8" + conventional-changelog-writer "^6.0.0" + conventional-commits-parser "^4.0.0" + dateformat "^3.0.3" + get-pkg-repo "^4.2.1" + git-raw-commits "^3.0.0" git-remote-origin-url "^2.0.0" - git-semver-tags "^4.1.1" - lodash "^4.17.15" - normalize-package-data "^3.0.0" - q "^1.5.1" + git-semver-tags "^5.0.0" + normalize-package-data "^3.0.3" read-pkg "^3.0.0" read-pkg-up "^3.0.0" - shelljs "^0.8.3" - through2 "^4.0.0" -conventional-changelog-preset-loader@^2.3.4: - version "2.3.4" - resolved "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz#14a855abbffd59027fd602581f1f34d9862ea44c" - integrity sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g== +conventional-changelog-preset-loader@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-3.0.0.tgz#14975ef759d22515d6eabae6396c2ae721d4c105" + integrity sha512-qy9XbdSLmVnwnvzEisjxdDiLA4OmV3o8db+Zdg4WiFw14fP3B6XNz98X0swPPpkTd/pc1K7+adKgEDM1JCUMiA== -conventional-changelog-writer@^4.0.18: - version "4.1.0" - resolved "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.1.0.tgz#1ca7880b75aa28695ad33312a1f2366f4b12659f" - integrity sha512-WwKcUp7WyXYGQmkLsX4QmU42AZ1lqlvRW9mqoyiQzdD+rJWbTepdWoKJuwXTS+yq79XKnQNa93/roViPQrAQgw== +conventional-changelog-writer@^6.0.0: + version "6.0.1" + resolved "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-6.0.1.tgz#d8d3bb5e1f6230caed969dcc762b1c368a8f7b01" + integrity sha512-359t9aHorPw+U+nHzUXHS5ZnPBOizRxfQsWT5ZDHBfvfxQOAik+yfuhKXG66CN5LEWPpMNnIMHUTCKeYNprvHQ== dependencies: - compare-func "^2.0.0" - conventional-commits-filter "^2.0.7" - dateformat "^3.0.0" - handlebars "^4.7.6" + conventional-commits-filter "^3.0.0" + dateformat "^3.0.3" + handlebars "^4.7.7" json-stringify-safe "^5.0.1" - lodash "^4.17.15" - meow "^8.0.0" - semver "^6.0.0" - split "^1.0.0" - through2 "^4.0.0" + meow "^8.1.2" + semver "^7.0.0" + split "^1.0.1" conventional-commit-types@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz#7c9214e58eae93e85dd66dbfbafe7e4fffa2365b" integrity sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg== -conventional-commits-filter@^2.0.7: - version "2.0.7" - resolved "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz#f8d9b4f182fce00c9af7139da49365b136c8a0b3" - integrity sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA== +conventional-commits-filter@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-3.0.0.tgz#bf1113266151dd64c49cd269e3eb7d71d7015ee2" + integrity sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q== dependencies: lodash.ismatch "^4.4.0" - modify-values "^1.0.0" + modify-values "^1.0.1" -conventional-commits-parser@^3.0.0, conventional-commits-parser@^3.2.0: - version "3.2.1" - resolved "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.1.tgz#ba44f0b3b6588da2ee9fd8da508ebff50d116ce2" - integrity sha512-OG9kQtmMZBJD/32NEw5IhN5+HnBqVjy03eC+I71I0oQRFA5rOgA4OtPOYG7mz1GkCfCNxn3gKIX8EiHJYuf1cA== +conventional-commits-parser@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz#02ae1178a381304839bce7cea9da5f1b549ae505" + integrity sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg== dependencies: - JSONStream "^1.0.4" + JSONStream "^1.3.5" is-text-path "^1.0.1" - lodash "^4.17.15" - meow "^8.0.0" - split2 "^3.0.0" - through2 "^4.0.0" - trim-off-newlines "^1.0.0" + meow "^8.1.2" + split2 "^3.2.2" -conventional-recommended-bump@^6.1.0: - version "6.1.0" - resolved "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz#cfa623285d1de554012f2ffde70d9c8a22231f55" - integrity sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw== +conventional-commits-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz#57f3594b81ad54d40c1b4280f04554df28627d9a" + integrity sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA== + dependencies: + JSONStream "^1.3.5" + is-text-path "^2.0.0" + meow "^12.0.1" + split2 "^4.0.0" + +conventional-recommended-bump@7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-7.0.1.tgz#ec01f6c7f5d0e2491c2d89488b0d757393392424" + integrity sha512-Ft79FF4SlOFvX4PkwFDRnaNiIVX7YbmqGU0RwccUaiGvgp3S0a8ipR2/Qxk31vclDNM+GSdJOVs2KrsUCjblVA== dependencies: concat-stream "^2.0.0" - conventional-changelog-preset-loader "^2.3.4" - conventional-commits-filter "^2.0.7" - conventional-commits-parser "^3.2.0" - git-raw-commits "^2.0.8" - git-semver-tags "^4.1.1" - meow "^8.0.0" - q "^1.5.1" + conventional-changelog-preset-loader "^3.0.0" + conventional-commits-filter "^3.0.0" + conventional-commits-parser "^4.0.0" + git-raw-commits "^3.0.0" + git-semver-tags "^5.0.0" + meow "^8.1.2" convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.7.0" @@ -10684,6 +10417,13 @@ core-util-is@~1.0.0: resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== +cosmiconfig-typescript-loader@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-5.0.0.tgz#0d3becfe022a871f7275ceb2397d692e06045dc8" + integrity sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA== + dependencies: + jiti "^1.19.1" + cosmiconfig@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" @@ -10717,6 +10457,26 @@ cosmiconfig@^7.0.1: path-type "^4.0.0" yaml "^1.10.0" +cosmiconfig@^8.2.0: + version "8.3.6" + resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" + integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA== + dependencies: + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" + path-type "^4.0.0" + +cosmiconfig@^9.0.0: + version "9.0.0" + resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz#34c3fc58287b915f3ae905ab6dc3de258b55ad9d" + integrity sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg== + dependencies: + env-paths "^2.2.1" + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" + cp-file@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/cp-file/-/cp-file-7.0.0.tgz#b9454cfd07fe3b974ab9ea0e5f29655791a9b8cd" @@ -11038,13 +10798,6 @@ csstype@^3.0.2: resolved "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz#2a5fb75e1015e84dd15692f71e89a1450290950b" integrity sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g== -currently-unhandled@^0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= - dependencies: - array-find-index "^1.0.1" - cyclist@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" @@ -11064,7 +10817,7 @@ cz-conventional-changelog@3.2.0: optionalDependencies: "@commitlint/load" ">6.1.1" -cz-conventional-changelog@^3.3.0: +cz-conventional-changelog@3.3.0, cz-conventional-changelog@^3.3.0: version "3.3.0" resolved "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz#9246947c90404149b3fe2cf7ee91acad3b7d22d2" integrity sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw== @@ -11088,6 +10841,11 @@ dargs@^7.0.0: resolved "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg== +dargs@^8.0.0: + version "8.1.0" + resolved "https://registry.npmjs.org/dargs/-/dargs-8.1.0.tgz#a34859ea509cbce45485e5aa356fef70bfcc7272" + integrity sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw== + dashdash@^1.12.0: version "1.14.1" resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -11122,7 +10880,7 @@ data-urls@^3.0.2: whatwg-mimetype "^3.0.0" whatwg-url "^11.0.0" -dateformat@^3.0.0: +dateformat@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== @@ -11148,11 +10906,6 @@ debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.5, debug@^3.2.6: dependencies: ms "^2.1.1" -debuglog@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" - integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= - decamelize-keys@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" @@ -11161,7 +10914,7 @@ decamelize-keys@^1.1.0: decamelize "^1.1.0" map-obj "^1.0.0" -decamelize@^1.1.0, decamelize@^1.1.2, decamelize@^1.2.0: +decamelize@^1.1.0, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= @@ -11250,6 +11003,11 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + define-properties@^1.1.2, define-properties@^1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -11312,12 +11070,12 @@ depd@2.0.0, depd@^2.0.0, depd@~2.0.0: resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== -depd@^1.1.2, depd@~1.1.2: +depd@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= -deprecation@^2.0.0, deprecation@^2.3.1: +deprecation@^2.0.0: version "2.3.1" resolved "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== @@ -11347,11 +11105,16 @@ detect-file@^1.0.0: resolved "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= -detect-indent@6.0.0, detect-indent@^6.0.0: +detect-indent@6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz#0abd0f549f69fc6659a254fe96786186b6f528fd" integrity sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA== +detect-indent@6.1.0: + version "6.1.0" + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" + integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== + detect-indent@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-0.2.0.tgz#042914498979ac2d9f3c73e4ff3e6877d3bc92b6" @@ -11401,14 +11164,6 @@ detect-port@^1.3.0: address "^1.0.1" debug "^2.6.0" -dezalgo@^1.0.0: - version "1.0.3" - resolved "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" - integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= - dependencies: - asap "^2.0.0" - wrappy "1" - diff-sequences@^24.9.0: version "24.9.0" resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5" @@ -11429,6 +11184,11 @@ diff-sequences@^27.4.0: resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.4.0.tgz#d783920ad8d06ec718a060d00196dfef25b132a5" integrity sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww== +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + diff@5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" @@ -11647,18 +11407,16 @@ dot-prop@^5.1.0: dependencies: is-obj "^2.0.0" -dot-prop@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" - integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== - dependencies: - is-obj "^2.0.0" - dotenv-expand@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== +dotenv-expand@~10.0.0: + version "10.0.0" + resolved "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz#12605d00fb0af6d0a592e6558585784032e4ef37" + integrity sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A== + dotenv@^10.0.0: version "10.0.0" resolved "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" @@ -11669,6 +11427,11 @@ dotenv@^8.0.0: resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== +dotenv@~16.3.1: + version "16.3.2" + resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.3.2.tgz#3cb611ce5a63002dbabf7c281bc331f69d28f03f" + integrity sha512-HTlk5nmhkm8F6JcdXvHIzaorzCoziNQT9mGxLPVXW8wJF1TiGSL60ZGB4gHWabHOaMmWmhvk2/lPHfnBiT78AQ== + downshift@^6.0.15: version "6.1.3" resolved "https://registry.npmjs.org/downshift/-/downshift-6.1.3.tgz#e794b7805d24810968f21e81ad6bdd9f3fdc40da" @@ -11715,6 +11478,11 @@ duplexify@^3.4.2, duplexify@^3.6.0: readable-stream "^2.0.0" stream-shift "^1.0.0" +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -11728,6 +11496,13 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== +ejs@^3.1.7: + version "3.1.9" + resolved "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361" + integrity sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ== + dependencies: + jake "^10.8.5" + electron-to-chromium@^1.3.564: version "1.3.896" resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.896.tgz#4a94efe4870b1687eafd5c378198a49da06e8a1b" @@ -11798,6 +11573,11 @@ emoji-regex@^9.0.0: resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.1.tgz#c9b25604256bb3428964bead3ab63069d736f7ee" integrity sha512-117l1H6U4X3Krn+MrzYrL57d5H7siRHWraBs7s+LjRuFK7Fe7hJqnJ0skWlinqsycVLU5YAo6L8CsEYQ0V5prg== +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + emojis-list@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" @@ -11817,7 +11597,7 @@ encodeurl@^1.0.2, encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== -encoding@^0.1.12: +encoding@^0.1.13: version "0.1.13" resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== @@ -11849,7 +11629,7 @@ enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.1, enhanced-resolve@^4.5.0: memory-fs "^0.5.0" tapable "^1.0.0" -enquirer@^2.3.5: +enquirer@^2.3.5, enquirer@~2.3.6: version "2.3.6" resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== @@ -11889,7 +11669,12 @@ env-paths@^2.2.0: resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz#cdca557dc009152917d6166e2febe1f039685e43" integrity sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA== -envinfo@^7.7.4: +env-paths@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + +envinfo@7.8.1: version "7.8.1" resolved "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== @@ -12437,6 +12222,21 @@ exec-sh@^0.3.2: resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" integrity sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A== +execa@5.0.0, execa@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz#4029b0007998a841fbd1032e5f4de86a3c1e3376" + integrity sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + execa@^0.7.0: version "0.7.0" resolved "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" @@ -12492,20 +12292,20 @@ execa@^3.2.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" -execa@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz#4029b0007998a841fbd1032e5f4de86a3c1e3376" - integrity sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ== +execa@^8.0.1: + version "8.0.1" + resolved "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" + integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg== dependencies: cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" + get-stream "^8.0.1" + human-signals "^5.0.0" + is-stream "^3.0.0" merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^4.1.0" + strip-final-newline "^3.0.0" execall@^2.0.0: version "2.0.0" @@ -12575,6 +12375,11 @@ expect@^27.4.2: jest-message-util "^27.4.2" jest-regex-util "^27.4.0" +exponential-backoff@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6" + integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== + express@^4.17.1: version "4.18.2" resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" @@ -12805,6 +12610,13 @@ figgy-pudding@^3.5.1: resolved "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== +figures@3.2.0, figures@^3.0.0: + version "3.2.0" + resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + figures@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -12812,13 +12624,6 @@ figures@^2.0.0: dependencies: escape-string-regexp "^1.0.5" -figures@^3.0.0: - version "3.2.0" - resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -12848,6 +12653,13 @@ file-uri-to-path@1.0.0: resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== +filelist@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" + integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q== + dependencies: + minimatch "^5.0.1" + filename-reserved-regex@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-1.0.0.tgz#e61cf805f0de1c984567d0386dc5df50ee5af7e4" @@ -12906,11 +12718,6 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -filter-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" - integrity sha1-mzERErxsYSehbgFsbF1/GeCAXFs= - finalhandler@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" @@ -12950,6 +12757,14 @@ find-node-modules@2.0.0: findup-sync "^3.0.0" merge "^1.2.1" +find-node-modules@^2.1.2: + version "2.1.3" + resolved "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.3.tgz#3c976cff2ca29ee94b4f9eafc613987fc4c0ee44" + integrity sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg== + dependencies: + findup-sync "^4.0.0" + merge "^2.1.1" + find-root@1.1.0, find-root@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" @@ -12971,14 +12786,6 @@ find-up@5.0.0, find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" @@ -12993,6 +12800,15 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" +find-up@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz#e8dec1455f74f78d888ad65bf7ca13dd2b4e66fb" + integrity sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g== + dependencies: + locate-path "^7.2.0" + path-exists "^5.0.0" + unicorn-magic "^0.1.0" + findup-sync@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1" @@ -13003,6 +12819,16 @@ findup-sync@^3.0.0: micromatch "^3.0.4" resolve-dir "^1.0.1" +findup-sync@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz#956c9cdde804052b881b428512905c4a5f2cdef0" + integrity sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ== + dependencies: + detect-file "^1.0.0" + is-glob "^4.0.0" + micromatch "^4.0.2" + resolve-dir "^1.0.1" + findup@^0.1.5: version "0.1.5" resolved "https://registry.npmjs.org/findup/-/findup-0.1.5.tgz#8ad929a3393bac627957a7e5de4623b06b0e2ceb" @@ -13054,6 +12880,11 @@ follow-redirects@^1.0.0, follow-redirects@^1.14.0, follow-redirects@^1.14.4: resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc" integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA== +follow-redirects@^1.15.6: + version "1.15.6" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== + for-each@^0.3.3: version "0.3.3" resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" @@ -13066,6 +12897,14 @@ for-in@^1.0.2: resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= +foreground-child@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" + integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -13193,6 +13032,16 @@ fs-extra@8.1.0, fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" +fs-extra@9.1.0, fs-extra@^9.0.0, fs-extra@^9.0.1: + version "9.1.0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs-extra@^0.30.0: version "0.30.0" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" @@ -13213,30 +13062,29 @@ fs-extra@^10.0.0: jsonfile "^6.0.1" universalify "^2.0.0" -fs-extra@^9.0.0, fs-extra@^9.0.1, fs-extra@^9.1.0: - version "9.1.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" - integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== +fs-extra@^11.1.0, fs-extra@^11.1.1: + version "11.2.0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b" + integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw== dependencies: - at-least-node "^1.0.0" graceful-fs "^4.2.0" jsonfile "^6.0.1" universalify "^2.0.0" -fs-minipass@^1.2.7: - version "1.2.7" - resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" - integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== - dependencies: - minipass "^2.6.0" - -fs-minipass@^2.0.0, fs-minipass@^2.1.0: +fs-minipass@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== dependencies: minipass "^3.0.0" +fs-minipass@^3.0.0: + version "3.0.3" + resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz#79a85981c4dc120065e96f62086bf6f9dc26cc54" + integrity sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw== + dependencies: + minipass "^7.0.3" + fs-monkey@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.1.tgz#4a82f36944365e619f4454d9fff106553067b781" @@ -13280,6 +13128,11 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + function.name-polyfill@^1.0.6: version "1.0.6" resolved "https://registry.npmjs.org/function.name-polyfill/-/function.name-polyfill-1.0.6.tgz#c54e37cae0a77dfcb49d47982815b0826b5c60d9" @@ -13325,19 +13178,19 @@ gauge@^3.0.0: strip-ansi "^6.0.1" wide-align "^1.1.2" -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= +gauge@^4.0.3: + version "4.0.4" + resolved "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce" + integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg== dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.3" + console-control-strings "^1.1.0" + has-unicode "^2.0.1" + signal-exit "^3.0.7" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.5" gensync@^1.0.0-beta.1, gensync@^1.0.0-beta.2: version "1.0.0-beta.2" @@ -13387,36 +13240,35 @@ get-package-type@^0.1.0: resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== -get-pkg-repo@^1.0.0: - version "1.4.0" - resolved "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-1.4.0.tgz#c73b489c06d80cc5536c2c853f9e05232056972d" - integrity sha1-xztInAbYDMVTbCyFP54FIyBWly0= +get-pkg-repo@^4.2.1: + version "4.2.1" + resolved "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz#75973e1c8050c73f48190c52047c4cee3acbf385" + integrity sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA== dependencies: - hosted-git-info "^2.1.4" - meow "^3.3.0" - normalize-package-data "^2.3.0" - parse-github-repo-url "^1.3.0" + "@hutson/parse-repository-url" "^3.0.0" + hosted-git-info "^4.0.0" through2 "^2.0.0" + yargs "^16.2.0" -get-port@^5.1.1: +get-port@5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== -get-stdin@8.0.0, get-stdin@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" - integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== - get-stdin@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-0.1.0.tgz#5998af24aafc802d15c82c685657eeb8b10d4a91" integrity sha1-WZivJKr8gC0VyCxoVlfuuLENSpE= -get-stdin@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= +get-stdin@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" + integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== + +get-stream@6.0.0, get-stream@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz#3e0012cb6827319da2706e601a1583e8629a6718" + integrity sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg== get-stream@^3.0.0: version "3.0.0" @@ -13437,10 +13289,10 @@ get-stream@^5.0.0: dependencies: pump "^3.0.0" -get-stream@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz#3e0012cb6827319da2706e601a1583e8629a6718" - integrity sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg== +get-stream@^8.0.1: + version "8.0.1" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" + integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== get-symbol-description@^1.0.0: version "1.0.0" @@ -13488,16 +13340,23 @@ gh-pages@^3.2.3: fs-extra "^8.1.0" globby "^6.1.0" -git-raw-commits@^2.0.0, git-raw-commits@^2.0.8: - version "2.0.10" - resolved "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.10.tgz#e2255ed9563b1c9c3ea6bd05806410290297bbc1" - integrity sha512-sHhX5lsbG9SOO6yXdlwgEMQ/ljIn7qMpAbJZCGfXX2fq5T8M5SrDnpYk9/4HswTildcIqatsWa91vty6VhWSaQ== +git-raw-commits@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-3.0.0.tgz#5432f053a9744f67e8db03dbc48add81252cfdeb" + integrity sha512-b5OHmZ3vAgGrDn/X0kS+9qCfNKWe4K/jFnhwzVWWg0/k5eLa3060tZShrRg8Dja5kPc+YjS0Gc6y7cRr44Lpjw== dependencies: dargs "^7.0.0" - lodash "^4.17.15" - meow "^8.0.0" - split2 "^3.0.0" - through2 "^4.0.0" + meow "^8.1.2" + split2 "^3.2.2" + +git-raw-commits@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-4.0.0.tgz#b212fd2bff9726d27c1283a1157e829490593285" + integrity sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ== + dependencies: + dargs "^8.0.0" + meow "^12.0.1" + split2 "^4.0.0" git-remote-origin-url@^2.0.0: version "2.0.0" @@ -13507,28 +13366,28 @@ git-remote-origin-url@^2.0.0: gitconfiglocal "^1.0.0" pify "^2.3.0" -git-semver-tags@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz#63191bcd809b0ec3e151ba4751c16c444e5b5780" - integrity sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA== +git-semver-tags@^5.0.0: + version "5.0.1" + resolved "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-5.0.1.tgz#db748aa0e43d313bf38dcd68624d8443234e1c15" + integrity sha512-hIvOeZwRbQ+7YEUmCkHqo8FOLQZCEn18yevLHADlFPZY02KJGsu5FZt9YW/lybfK2uhWFI7Qg/07LekJiTv7iA== dependencies: - meow "^8.0.0" - semver "^6.0.0" + meow "^8.1.2" + semver "^7.0.0" -git-up@^4.0.0: - version "4.0.2" - resolved "https://registry.npmjs.org/git-up/-/git-up-4.0.2.tgz#10c3d731051b366dc19d3df454bfca3f77913a7c" - integrity sha512-kbuvus1dWQB2sSW4cbfTeGpCMd8ge9jx9RKnhXhuJ7tnvT+NIrTVfYZxjtflZddQYcmdOTlkAcjmx7bor+15AQ== +git-up@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz#bace30786e36f56ea341b6f69adfd83286337467" + integrity sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ== dependencies: - is-ssh "^1.3.0" - parse-url "^5.0.0" + is-ssh "^1.4.0" + parse-url "^8.1.0" -git-url-parse@^11.4.4: - version "11.4.4" - resolved "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.4.4.tgz#5d747debc2469c17bc385719f7d0427802d83d77" - integrity sha512-Y4o9o7vQngQDIU9IjyCmRJBin5iYjI5u9ZITnddRZpD7dcCFQj2sL2XuMNbLRE4b4B/4ENPsp2Q8P44fjAZ0Pw== +git-url-parse@13.1.0: + version "13.1.0" + resolved "https://registry.npmjs.org/git-url-parse/-/git-url-parse-13.1.0.tgz#07e136b5baa08d59fabdf0e33170de425adf07b4" + integrity sha512-5FvPJP/70WkIprlUZ33bm4UAaFdjcLkJLpWft1BeZKqwR0uhhNGoKwlUaPtVb4LxCSQ++erHapRak9kWGj+FCA== dependencies: - git-up "^4.0.0" + git-up "^7.0.0" gitconfiglocal@^1.0.0: version "1.0.0" @@ -13544,6 +13403,13 @@ github-slugger@^1.0.0, github-slugger@^1.2.1: dependencies: emoji-regex ">=6.0.0 <=6.1.1" +glob-parent@5.1.2, glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" @@ -13559,13 +13425,6 @@ glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@^5.1.1, glob-parent@~5.1.0: dependencies: is-glob "^4.0.1" -glob-parent@^5.1.2, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - glob-promise@^3.4.0: version "3.4.0" resolved "https://registry.npmjs.org/glob-promise/-/glob-promise-3.4.0.tgz#b6b8f084504216f702dc2ce8c9bc9ac8866fdb20" @@ -13603,10 +13462,33 @@ glob@7.2.0: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.4" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@7.2.3: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" once "^1.3.0" path-is-absolute "^1.0.0" +glob@^10.2.2, glob@^10.3.10: + version "10.3.12" + resolved "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz#3a65c363c2e9998d220338e88a5f6ac97302960b" + integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.6" + minimatch "^9.0.1" + minipass "^7.0.4" + path-scurry "^1.10.2" + glob@^6.0.4: version "6.0.4" resolved "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" @@ -13630,6 +13512,34 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, gl once "^1.3.0" path-is-absolute "^1.0.0" +glob@^8.0.1: + version "8.1.0" + resolved "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + +glob@^9.2.0: + version "9.3.5" + resolved "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz#ca2ed8ca452781a3009685607fdf025a899dfe21" + integrity sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q== + dependencies: + fs.realpath "^1.0.0" + minimatch "^8.0.2" + minipass "^4.2.4" + path-scurry "^1.6.1" + +global-directory@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz#4d7ac7cfd2cb73f304c53b8810891748df5e361e" + integrity sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q== + dependencies: + ini "4.1.1" + global-dirs@^0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" @@ -13724,6 +13634,18 @@ globby@11.0.1: merge2 "^1.3.0" slash "^3.0.0" +globby@11.1.0, globby@^11.0.4, globby@^11.1.0: + version "11.1.0" + resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + globby@^11.0.1, globby@^11.0.2: version "11.0.2" resolved "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz#1af538b766a3b540ebfb58a32b2e2d5897321d83" @@ -13736,18 +13658,6 @@ globby@^11.0.1, globby@^11.0.2: merge2 "^1.3.0" slash "^3.0.0" -globby@^11.0.4, globby@^11.1.0: - version "11.1.0" - resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - globby@^6.1.0: version "6.1.0" resolved "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" @@ -13792,7 +13702,12 @@ good-listener@^1.2.2: dependencies: delegate "^3.1.2" -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.3, graceful-fs@^4.2.4: +graceful-fs@4.2.11, graceful-fs@^4.2.6: + version "4.2.11" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4: version "4.2.6" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== @@ -13822,7 +13737,7 @@ handle-thing@^2.0.0: resolved "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== -handlebars@^4.3.1, handlebars@^4.5.1, handlebars@^4.7.6, handlebars@^4.7.7: +handlebars@^4.3.1, handlebars@^4.5.1, handlebars@^4.7.7: version "4.7.7" resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== @@ -13896,10 +13811,10 @@ has-tostringtag@^1.0.0: dependencies: has-symbols "^1.0.2" -has-unicode@^2.0.0, has-unicode@^2.0.1: +has-unicode@2.0.1, has-unicode@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== has-value@^0.3.1: version "0.3.1" @@ -13961,6 +13876,13 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" +hasown@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + hast-to-hyperscript@^9.0.0: version "9.0.1" resolved "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz#9b67fd188e4c81e8ad66f803855334173920218d" @@ -14098,6 +14020,13 @@ hosted-git-info@^3.0.6: dependencies: lru-cache "^6.0.0" +hosted-git-info@^4.0.0: + version "4.1.0" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" + integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== + dependencies: + lru-cache "^6.0.0" + hosted-git-info@^4.0.1: version "4.0.2" resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961" @@ -14105,6 +14034,20 @@ hosted-git-info@^4.0.1: dependencies: lru-cache "^6.0.0" +hosted-git-info@^6.0.0: + version "6.1.1" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz#629442c7889a69c05de604d52996b74fe6f26d58" + integrity sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w== + dependencies: + lru-cache "^7.5.1" + +hosted-git-info@^7.0.0: + version "7.0.1" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz#9985fcb2700467fecf7f33a4d4874e30680b5322" + integrity sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA== + dependencies: + lru-cache "^10.0.1" + hpack.js@^2.1.6: version "2.1.6" resolved "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" @@ -14227,7 +14170,7 @@ http-assert@^1.3.0: deep-equal "~1.0.1" http-errors "~1.8.0" -http-cache-semantics@^4.1.0: +http-cache-semantics@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== @@ -14292,6 +14235,14 @@ http-proxy-agent@^5.0.0: agent-base "6" debug "4" +http-proxy-agent@^7.0.0: + version "7.0.2" + resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" + integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + http-proxy-middleware@0.19.1: version "0.19.1" resolved "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" @@ -14349,6 +14300,14 @@ https-proxy-agent@^5.0.1: agent-base "6" debug "4" +https-proxy-agent@^7.0.1: + version "7.0.4" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz#8e97b841a029ad8ddc8731f26595bad868cb4168" + integrity sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg== + dependencies: + agent-base "^7.0.2" + debug "4" + human-signals@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" @@ -14359,6 +14318,11 @@ human-signals@^2.1.0: resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== +human-signals@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" + integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== + humanize-ms@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" @@ -14374,10 +14338,10 @@ humanize-url@^1.0.0: normalize-url "^1.0.0" strip-url-auth "^1.0.0" -husky@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz#810f11869adf51604c32ea577edbc377d7f9319e" - integrity sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ== +husky@^9.0.11: + version "9.0.11" + resolved "https://registry.npmjs.org/husky/-/husky-9.0.11.tgz#fc91df4c756050de41b3e478b2158b87c1e79af9" + integrity sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw== hyphenate-style-name@^1.0.3: version "1.0.4" @@ -14434,18 +14398,30 @@ iferr@^0.1.5: resolved "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= -ignore-walk@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" - integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== +ignore-walk@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/ignore-walk/-/ignore-walk-5.0.1.tgz#5f199e23e1288f518d90358d461387788a154776" + integrity sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw== dependencies: - minimatch "^3.0.4" + minimatch "^5.0.1" + +ignore-walk@^6.0.4: + version "6.0.4" + resolved "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz#89950be94b4f522225eb63a13c56badb639190e9" + integrity sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw== + dependencies: + minimatch "^9.0.0" ignore@^4.0.3, ignore@^4.0.6: version "4.0.6" resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +ignore@^5.0.4: + version "5.3.1" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== + ignore@^5.1.4: version "5.1.9" resolved "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz#9ec1a5cbe8e1446ec60d4420060d43aa6e7382fb" @@ -14478,7 +14454,7 @@ immer@8.0.1: resolved "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz#9c73db683e2b3975c424fb0572af5889877ae656" integrity sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA== -import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1: +import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1, import-fresh@^3.3.0: version "3.3.0" resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -14491,6 +14467,14 @@ import-lazy@^4.0.0: resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153" integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== +import-local@3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + import-local@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" @@ -14507,6 +14491,11 @@ import-local@^3.0.2: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" +import-meta-resolve@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.0.0.tgz#0b1195915689f60ab00f830af0f15cc841e8919e" + integrity sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA== + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -14519,13 +14508,6 @@ indefinite-observable@^2.0.1: dependencies: symbol-observable "1.2.0" -indent-string@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" - integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= - dependencies: - repeating "^2.0.0" - indent-string@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" @@ -14569,24 +14551,28 @@ inherits@2.0.3: resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@^1.3.2, ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: +ini@4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz#d95b3d843b1e906e56d6747d5447904ff50ce7a1" + integrity sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g== + +ini@^1.3.2, ini@^1.3.4, ini@^1.3.5, ini@^1.3.8, ini@~1.3.0: version "1.3.8" resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -init-package-json@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/init-package-json/-/init-package-json-2.0.2.tgz#d81a7e6775af9b618f20bba288e440b8d1ce05f3" - integrity sha512-PO64kVeArePvhX7Ff0jVWkpnE1DfGRvaWcStYrPugcJz9twQGYibagKJuIMHCX7ENcp0M6LJlcjLBuLD5KeJMg== +init-package-json@5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/init-package-json/-/init-package-json-5.0.0.tgz#030cf0ea9c84cfc1b0dc2e898b45d171393e4b40" + integrity sha512-kBhlSheBfYmq3e0L1ii+VKe3zBTLL5lDCDWR+f9dLmEGSB3MqLlMlsolubSsyI88Bg6EA+BIMlomAnQ1SwgQBw== dependencies: - glob "^7.1.1" - npm-package-arg "^8.1.0" - promzard "^0.3.0" - read "~1.0.1" - read-package-json "^3.0.0" - semver "^7.3.2" + npm-package-arg "^10.0.0" + promzard "^1.0.0" + read "^2.0.0" + read-package-json "^6.0.0" + semver "^7.3.5" validate-npm-package-license "^3.0.4" - validate-npm-package-name "^3.0.0" + validate-npm-package-name "^5.0.0" inline-style-parser@0.1.1: version "0.1.1" @@ -14612,24 +14598,47 @@ inquirer@6.5.2: strip-ansi "^5.1.0" through "^2.3.6" -inquirer@^7.3.3: - version "7.3.3" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" - integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== +inquirer@8.2.5: + version "8.2.5" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz#d8654a7542c35a9b9e069d27e2df4858784d54f8" + integrity sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ== dependencies: ansi-escapes "^4.2.1" - chalk "^4.1.0" + chalk "^4.1.1" cli-cursor "^3.1.0" cli-width "^3.0.0" external-editor "^3.0.3" figures "^3.0.0" - lodash "^4.17.19" + lodash "^4.17.21" + mute-stream "0.0.8" + ora "^5.4.1" + run-async "^2.4.0" + rxjs "^7.5.5" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + wrap-ansi "^7.0.0" + +inquirer@^8.2.4: + version "8.2.6" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz#733b74888195d8d400a67ac332011b5fae5ea562" + integrity sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.1" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.21" mute-stream "0.0.8" + ora "^5.4.1" run-async "^2.4.0" - rxjs "^6.6.0" + rxjs "^7.5.5" string-width "^4.1.0" strip-ansi "^6.0.0" through "^2.3.6" + wrap-ansi "^6.0.1" internal-ip@^4.3.0: version "4.3.0" @@ -14670,6 +14679,14 @@ invert-kv@^2.0.0: resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== +ip-address@^9.0.5: + version "9.0.5" + resolved "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a" + integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g== + dependencies: + jsbn "1.1.0" + sprintf-js "^1.1.3" + ip-regex@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" @@ -14785,6 +14802,13 @@ is-callable@^1.2.4: resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== +is-ci@3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz#db6ecbed1bd659c43dac0f45661e7674103d1867" + integrity sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ== + dependencies: + ci-info "^3.2.0" + is-ci@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" @@ -14799,6 +14823,13 @@ is-core-module@^2.2.0: dependencies: has "^1.0.3" +is-core-module@^2.5.0, is-core-module@^2.8.1: + version "2.13.1" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -14846,7 +14877,7 @@ is-directory@^0.3.1: resolved "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= -is-docker@^2.0.0: +is-docker@^2.0.0, is-docker@^2.1.1: version "2.2.1" resolved "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== @@ -14876,11 +14907,6 @@ is-extglob@^2.1.0, is-extglob@^2.1.1: resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= -is-finite@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" - integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== - is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" @@ -15105,22 +15131,27 @@ is-shared-array-buffer@^1.0.1: resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== -is-ssh@^1.3.0: - version "1.3.2" - resolved "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.2.tgz#a4b82ab63d73976fd8263cceee27f99a88bdae2b" - integrity sha512-elEw0/0c2UscLrNG+OAorbP539E3rhliKPg+hDMWN9VwrDXfYK+4PBEykDPfxlYYtQvl84TascnQyobfQLHEhQ== +is-ssh@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.0.tgz#4f8220601d2839d8fa624b3106f8e8884f01b8b2" + integrity sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ== dependencies: - protocols "^1.1.0" + protocols "^2.0.1" + +is-stream@2.0.0, is-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" + integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== is-stream@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= -is-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" - integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== is-string@^1.0.5: version "1.0.5" @@ -15153,6 +15184,13 @@ is-text-path@^1.0.1: dependencies: text-extensions "^1.0.0" +is-text-path@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz#b2484e2b720a633feb2e85b67dc193ff72c75636" + integrity sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw== + dependencies: + text-extensions "^2.0.0" + is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -15163,7 +15201,7 @@ is-unicode-supported@^0.1.0: resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-utf8@^0.2.0, is-utf8@^0.2.1: +is-utf8@^0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= @@ -15205,7 +15243,7 @@ is-wsl@^1.1.0: resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= -is-wsl@^2.1.1: +is-wsl@^2.1.1, is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -15232,6 +15270,11 @@ isexe@^2.0.0: resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= +isexe@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz#4a407e2bd78ddfb14bea0c27c6f7072dde775f0d" + integrity sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ== + isobject@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -15353,6 +15396,25 @@ iterate-value@^1.0.2: es-get-iterator "^1.0.2" iterate-iterator "^1.0.1" +jackspeak@^2.3.6: + version "2.3.6" + resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +jake@^10.8.5: + version "10.8.7" + resolved "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz#63a32821177940c33f356e0ba44ff9d34e1c7d8f" + integrity sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w== + dependencies: + async "^3.2.3" + chalk "^4.0.2" + filelist "^1.0.4" + minimatch "^3.1.2" + javascript-stringify@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.0.1.tgz#6ef358035310e35d667c675ed63d3eb7c1aa19e5" @@ -15553,6 +15615,16 @@ jest-config@^27.4.5: pretty-format "^27.4.2" slash "^3.0.0" +"jest-diff@>=29.4.3 < 30", jest-diff@^29.4.1: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + jest-diff@^24.9.0: version "24.9.0" resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da" @@ -15749,6 +15821,11 @@ jest-get-type@^27.0.1, jest-get-type@^27.4.0: resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz#7503d2663fffa431638337b3998d39c5e928e9b5" integrity sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ== +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + jest-haste-map@^24.9.0: version "24.9.0" resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz#b38a5d64274934e21fa417ae9a9fbeb77ceaac7d" @@ -16582,6 +16659,11 @@ jest@^25.1.0: import-local "^3.0.2" jest-cli "^25.5.4" +jiti@^1.19.1: + version "1.21.0" + resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" + integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== + joi@^17.4.0: version "17.5.0" resolved "https://registry.npmjs.org/joi/-/joi-17.5.0.tgz#7e66d0004b5045d971cf416a55fb61d33ac6e011" @@ -16603,14 +16685,14 @@ js-string-escape@^1.0.1: resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@4.1.0: +js-yaml@4.1.0, js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: argparse "^2.0.1" -js-yaml@^3.13.1: +js-yaml@^3.10.0, js-yaml@^3.13.1: version "3.14.1" resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== @@ -16618,6 +16700,11 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +jsbn@1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" + integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -16796,6 +16883,11 @@ json-parse-even-better-errors@^2.3.0: resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== +json-parse-even-better-errors@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz#02bb29fb5da90b5444581749c22cedd3597c6cb0" + integrity sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg== + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -16845,6 +16937,11 @@ json5@^2.2.2: resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== +jsonc-parser@3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" + integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== + jsonfile@^2.1.0: version "2.4.0" resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" @@ -17137,29 +17234,85 @@ left-pad@^1.3.0: resolved "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== -lerna@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/lerna/-/lerna-4.0.0.tgz#b139d685d50ea0ca1be87713a7c2f44a5b678e9e" - integrity sha512-DD/i1znurfOmNJb0OBw66NmNqiM8kF6uIrzrJ0wGE3VNdzeOhz9ziWLYiRaZDGGwgbcjOo6eIfcx9O5Qynz+kg== - dependencies: - "@lerna/add" "4.0.0" - "@lerna/bootstrap" "4.0.0" - "@lerna/changed" "4.0.0" - "@lerna/clean" "4.0.0" - "@lerna/cli" "4.0.0" - "@lerna/create" "4.0.0" - "@lerna/diff" "4.0.0" - "@lerna/exec" "4.0.0" - "@lerna/import" "4.0.0" - "@lerna/info" "4.0.0" - "@lerna/init" "4.0.0" - "@lerna/link" "4.0.0" - "@lerna/list" "4.0.0" - "@lerna/publish" "4.0.0" - "@lerna/run" "4.0.0" - "@lerna/version" "4.0.0" - import-local "^3.0.2" - npmlog "^4.1.2" +lerna@^8.1.2: + version "8.1.2" + resolved "https://registry.npmjs.org/lerna/-/lerna-8.1.2.tgz#441e8078d0b68557b4ef5b33202a16a6bc2a50d3" + integrity sha512-RCyBAn3XsqqvHbz3TxLfD7ylqzCi1A2UJnFEZmhURgx589vM3qYWQa/uOMeEEf565q6cAdtmulITciX1wgkAtw== + dependencies: + "@lerna/create" "8.1.2" + "@npmcli/run-script" "7.0.2" + "@nx/devkit" ">=17.1.2 < 19" + "@octokit/plugin-enterprise-rest" "6.0.1" + "@octokit/rest" "19.0.11" + byte-size "8.1.1" + chalk "4.1.0" + clone-deep "4.0.1" + cmd-shim "6.0.1" + columnify "1.6.0" + conventional-changelog-angular "7.0.0" + conventional-changelog-core "5.0.1" + conventional-recommended-bump "7.0.1" + cosmiconfig "^8.2.0" + dedent "0.7.0" + envinfo "7.8.1" + execa "5.0.0" + fs-extra "^11.1.1" + get-port "5.1.1" + get-stream "6.0.0" + git-url-parse "13.1.0" + glob-parent "5.1.2" + globby "11.1.0" + graceful-fs "4.2.11" + has-unicode "2.0.1" + import-local "3.1.0" + ini "^1.3.8" + init-package-json "5.0.0" + inquirer "^8.2.4" + is-ci "3.0.1" + is-stream "2.0.0" + jest-diff ">=29.4.3 < 30" + js-yaml "4.1.0" + libnpmaccess "7.0.2" + libnpmpublish "7.3.0" + load-json-file "6.2.0" + lodash "^4.17.21" + make-dir "4.0.0" + minimatch "3.0.5" + multimatch "5.0.0" + node-fetch "2.6.7" + npm-package-arg "8.1.1" + npm-packlist "5.1.1" + npm-registry-fetch "^14.0.5" + npmlog "^6.0.2" + nx ">=17.1.2 < 19" + p-map "4.0.0" + p-map-series "2.1.0" + p-pipe "3.1.0" + p-queue "6.6.2" + p-reduce "2.1.0" + p-waterfall "2.1.1" + pacote "^17.0.5" + pify "5.0.0" + read-cmd-shim "4.0.0" + read-package-json "6.0.4" + resolve-from "5.0.0" + rimraf "^4.4.1" + semver "^7.3.8" + signal-exit "3.0.7" + slash "3.0.0" + ssri "^9.0.1" + strong-log-transformer "2.1.0" + tar "6.1.11" + temp-dir "1.0.0" + typescript ">=3 < 6" + upath "2.0.1" + uuid "^9.0.0" + validate-npm-package-license "3.0.4" + validate-npm-package-name "5.0.0" + write-file-atomic "5.0.1" + write-pkg "4.0.0" + yargs "17.7.2" + yargs-parser "21.1.1" less-loader@7.3.0: version "7.3.0" @@ -17208,26 +17361,27 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -libnpmaccess@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-4.0.1.tgz#17e842e03bef759854adf6eb6c2ede32e782639f" - integrity sha512-ZiAgvfUbvmkHoMTzdwmNWCrQRsDkOC+aM5BDfO0C9aOSwF3R1LdFDBD+Rer1KWtsoQYO35nXgmMR7OUHpDRxyA== +libnpmaccess@7.0.2: + version "7.0.2" + resolved "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-7.0.2.tgz#7f056c8c933dd9c8ba771fa6493556b53c5aac52" + integrity sha512-vHBVMw1JFMTgEk15zRsJuSAg7QtGGHpUSEfnbcRL1/gTBag9iEfJbyjpDmdJmwMhvpoLoNBtdAUCdGnaP32hhw== dependencies: - aproba "^2.0.0" - minipass "^3.1.1" - npm-package-arg "^8.0.0" - npm-registry-fetch "^9.0.0" + npm-package-arg "^10.1.0" + npm-registry-fetch "^14.0.3" -libnpmpublish@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-4.0.0.tgz#ad6413914e0dfd78df868ce14ba3d3a4cc8b385b" - integrity sha512-2RwYXRfZAB1x/9udKpZmqEzSqNd7ouBRU52jyG14/xG8EF+O9A62d7/XVR3iABEQHf1iYhkm0Oq9iXjrL3tsXA== - dependencies: - normalize-package-data "^3.0.0" - npm-package-arg "^8.1.0" - npm-registry-fetch "^9.0.0" - semver "^7.1.3" - ssri "^8.0.0" +libnpmpublish@7.3.0: + version "7.3.0" + resolved "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-7.3.0.tgz#2ceb2b36866d75a6cd7b4aa748808169f4d17e37" + integrity sha512-fHUxw5VJhZCNSls0KLNEG0mCD2PN1i14gH5elGOgiVnU3VgTcRahagYP2LKI1m0tFCJ+XrAm0zVYyF5RCbXzcg== + dependencies: + ci-info "^3.6.1" + normalize-package-data "^5.0.0" + npm-package-arg "^10.1.0" + npm-registry-fetch "^14.0.3" + proc-log "^3.0.0" + semver "^7.3.7" + sigstore "^1.4.0" + ssri "^10.0.1" lie@~3.3.0: version "3.3.0" @@ -17241,21 +17395,25 @@ lines-and-columns@^1.1.6: resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= +lines-and-columns@~2.0.3: + version "2.0.4" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz#d00318855905d2660d8c0822e3f5a4715855fc42" + integrity sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A== + listify@^1.0.0: version "1.0.3" resolved "https://registry.npmjs.org/listify/-/listify-1.0.3.tgz#a9335ac351c3d1aea515494ed746976eeb92248b" integrity sha512-083swF7iH7bx8666zdzBColpgEuy46HjN3r1isD4zV6Ix7FuHfb/2/WVnl4CH8hjuoWeFF7P5KkKNXUnJCFEJg== -load-json-file@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= +load-json-file@6.2.0: + version "6.2.0" + resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz#5c7770b42cafa97074ca2848707c61662f4251a1" + integrity sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ== dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" + graceful-fs "^4.1.15" + parse-json "^5.0.0" + strip-bom "^4.0.0" + type-fest "^0.6.0" load-json-file@^2.0.0: version "2.0.0" @@ -17277,16 +17435,6 @@ load-json-file@^4.0.0: pify "^3.0.0" strip-bom "^3.0.0" -load-json-file@^6.2.0: - version "6.2.0" - resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz#5c7770b42cafa97074ca2848707c61662f4251a1" - integrity sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ== - dependencies: - graceful-fs "^4.1.15" - parse-json "^5.0.0" - strip-bom "^4.0.0" - type-fest "^0.6.0" - loader-runner@^2.4.0: version "2.4.0" resolved "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" @@ -17354,10 +17502,17 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= +locate-path@^7.2.0: + version "7.2.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz#69cb1779bd90b35ab1e771e1f2f89a202c2a8a8a" + integrity sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA== + dependencies: + p-locate "^6.0.0" + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== lodash.debounce@^4.0.8: version "4.0.8" @@ -17384,35 +17539,45 @@ lodash.ismatch@^4.4.0: resolved "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc= +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.kebabcase@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" + integrity sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g== + lodash.map@^4.5.1: version "4.6.0" resolved "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" integrity sha1-dx7Hg540c9nEzeKLGTlMNWL09tM= -lodash.merge@4.6.2: +lodash.merge@4.6.2, lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.mergewith@^4.6.2: + version "4.6.2" + resolved "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" + integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== + +lodash.snakecase@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d" + integrity sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw== + lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= -lodash.template@^4.5.0: - version "4.5.0" - resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" - integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.templatesettings "^4.0.0" - -lodash.templatesettings@^4.0.0: - version "4.2.0" - resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" - integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== - dependencies: - lodash._reinterpolate "^3.0.0" +lodash.startcase@^4.4.0: + version "4.4.0" + resolved "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz#9436e34ed26093ed7ffae1936144350915d9add8" + integrity sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg== lodash.throttle@^4.1.1: version "4.1.1" @@ -17424,17 +17589,22 @@ lodash.truncate@^4.4.2: resolved "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= -lodash.uniq@4.5.0: +lodash.uniq@4.5.0, lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== -lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: +lodash.upperfirst@^4.3.1: + version "4.3.1" + resolved "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce" + integrity sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg== + +lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-symbols@4.1.0, log-symbols@^4.1.0: +log-symbols@4.1.0, log-symbols@^4.0.0, log-symbols@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== @@ -17488,14 +17658,6 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3 dependencies: js-tokens "^3.0.0 || ^4.0.0" -loud-rejection@^1.0.0: - version "1.6.0" - resolved "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= - dependencies: - currently-unhandled "^0.4.1" - signal-exit "^3.0.0" - loupe@^2.3.1: version "2.3.6" resolved "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" @@ -17531,6 +17693,11 @@ lowlight@^1.17.0: fault "^1.0.0" highlight.js "~10.6.0" +lru-cache@^10.0.1, lru-cache@^10.2.0: + version "10.2.0" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" + integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== + lru-cache@^4.0.1: version "4.1.5" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" @@ -17553,6 +17720,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lru-cache@^7.5.1, lru-cache@^7.7.1: + version "7.18.3" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" + integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== + lz-string@^1.4.4: version "1.4.4" resolved "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" @@ -17565,6 +17737,13 @@ magic-string@^0.25.7: dependencies: sourcemap-codec "^1.4.4" +make-dir@4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + make-dir@^2.0.0, make-dir@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" @@ -17580,26 +17759,43 @@ make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0: dependencies: semver "^6.0.0" -make-fetch-happen@^8.0.9: - version "8.0.14" - resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz#aaba73ae0ab5586ad8eaa68bd83332669393e222" - integrity sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ== +make-fetch-happen@^11.0.0, make-fetch-happen@^11.0.1, make-fetch-happen@^11.1.1: + version "11.1.1" + resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz#85ceb98079584a9523d4bf71d32996e7e208549f" + integrity sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w== dependencies: - agentkeepalive "^4.1.3" - cacache "^15.0.5" - http-cache-semantics "^4.1.0" - http-proxy-agent "^4.0.1" + agentkeepalive "^4.2.1" + cacache "^17.0.0" + http-cache-semantics "^4.1.1" + http-proxy-agent "^5.0.0" https-proxy-agent "^5.0.0" is-lambda "^1.0.1" - lru-cache "^6.0.0" - minipass "^3.1.3" - minipass-collect "^1.0.2" - minipass-fetch "^1.3.2" + lru-cache "^7.7.1" + minipass "^5.0.0" + minipass-fetch "^3.0.0" minipass-flush "^1.0.5" minipass-pipeline "^1.2.4" + negotiator "^0.6.3" promise-retry "^2.0.1" - socks-proxy-agent "^5.0.0" - ssri "^8.0.0" + socks-proxy-agent "^7.0.0" + ssri "^10.0.0" + +make-fetch-happen@^13.0.0: + version "13.0.0" + resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz#705d6f6cbd7faecb8eac2432f551e49475bfedf0" + integrity sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A== + dependencies: + "@npmcli/agent" "^2.0.0" + cacache "^18.0.0" + http-cache-semantics "^4.1.1" + is-lambda "^1.0.1" + minipass "^7.0.2" + minipass-fetch "^3.0.0" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + negotiator "^0.6.3" + promise-retry "^2.0.1" + ssri "^10.0.0" makeerror@1.0.x: version "1.0.11" @@ -17620,7 +17816,7 @@ map-cache@^0.2.2: resolved "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= -map-obj@^1.0.0, map-obj@^1.0.1: +map-obj@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= @@ -17796,23 +17992,12 @@ memorystream@^0.3.1: resolved "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI= -meow@^3.3.0: - version "3.7.0" - resolved "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" - integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= - dependencies: - camelcase-keys "^2.0.0" - decamelize "^1.1.2" - loud-rejection "^1.0.0" - map-obj "^1.0.1" - minimist "^1.1.3" - normalize-package-data "^2.3.4" - object-assign "^4.0.1" - read-pkg-up "^1.0.1" - redent "^1.0.0" - trim-newlines "^1.0.0" +meow@^12.0.1: + version "12.1.1" + resolved "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz#e558dddbab12477b69b2e9a2728c327f191bace6" + integrity sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw== -meow@^8.0.0: +meow@^8.1.2: version "8.1.2" resolved "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" integrity sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q== @@ -17867,6 +18052,11 @@ merge@^1.2.1: resolved "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== +merge@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz#59ef4bf7e0b3e879186436e8481c06a6c162ca98" + integrity sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w== + methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -17992,6 +18182,11 @@ mimic-fn@^2.0.0, mimic-fn@^2.1.0: resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + min-document@^2.19.0: version "2.19.0" resolved "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" @@ -18036,10 +18231,52 @@ minimalistic-crypto-utils@^1.0.1: dependencies: brace-expansion "^1.1.7" -minimatch@5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" - integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== +minimatch@3.0.5: + version "3.0.5" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz#4da8f1290ee0f0f8e83d60ca69f8f134068604a3" + integrity sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" + integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@9.0.3: + version "9.0.3" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^8.0.2: + version "8.0.4" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz#847c1b25c014d4e9a7f68aaf63dedd668a626229" + integrity sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.0, minimatch@^9.0.1, minimatch@^9.0.3: + version "9.0.4" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== dependencies: brace-expansion "^2.0.1" @@ -18057,15 +18294,20 @@ minimist@1.2.5: resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimist@1.2.7, minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: + version "1.2.7" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" + integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== + minimist@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/minimist/-/minimist-0.1.0.tgz#99df657a52574c21c9057497df742790b2b4c0de" integrity sha1-md9lelJXTCHJBXSX33QnkLK0wN4= -minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: - version "1.2.7" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" - integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== +minimist@^1.2.8: + version "1.2.8" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== minipass-collect@^1.0.2: version "1.0.2" @@ -18074,16 +18316,23 @@ minipass-collect@^1.0.2: dependencies: minipass "^3.0.0" -minipass-fetch@^1.3.0, minipass-fetch@^1.3.2: - version "1.3.3" - resolved "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.3.3.tgz#34c7cea038c817a8658461bf35174551dce17a0a" - integrity sha512-akCrLDWfbdAWkMLBxJEeWTdNsjML+dt5YgOI4gJ53vuO0vrmYQkUPxa6j6V65s9CcePIr2SSWqjT2EcrNseryQ== +minipass-collect@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz#1621bc77e12258a12c60d34e2276ec5c20680863" + integrity sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw== + dependencies: + minipass "^7.0.3" + +minipass-fetch@^3.0.0: + version "3.0.4" + resolved "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz#4d4d9b9f34053af6c6e597a64be8e66e42bf45b7" + integrity sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg== dependencies: - minipass "^3.1.0" + minipass "^7.0.3" minipass-sized "^1.0.3" - minizlib "^2.0.0" + minizlib "^2.1.2" optionalDependencies: - encoding "^0.1.12" + encoding "^0.1.13" minipass-flush@^1.0.5: version "1.0.5" @@ -18114,29 +18363,29 @@ minipass-sized@^1.0.3: dependencies: minipass "^3.0.0" -minipass@^2.6.0, minipass@^2.9.0: - version "2.9.0" - resolved "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" - integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - -minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: +minipass@^3.0.0, minipass@^3.1.1: version "3.1.3" resolved "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd" integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg== dependencies: yallist "^4.0.0" -minizlib@^1.3.3: - version "1.3.3" - resolved "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" - integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== - dependencies: - minipass "^2.9.0" +minipass@^4.2.4: + version "4.2.8" + resolved "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a" + integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ== + +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== -minizlib@^2.0.0, minizlib@^2.1.1: +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.0.4: + version "7.0.4" + resolved "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== + +minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== @@ -18173,15 +18422,6 @@ mkdirp-classic@^0.5.2: resolved "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== -mkdirp-infer-owner@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz#55d3b368e7d89065c38f32fd38e638f0ab61d316" - integrity sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw== - dependencies: - chownr "^2.0.0" - infer-owner "^1.0.4" - mkdirp "^1.0.3" - mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.4, mkdirp@^0.5.5: version "0.5.5" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" @@ -18222,7 +18462,7 @@ mocha@~10.0.0: yargs-parser "20.2.4" yargs-unparser "2.0.0" -modify-values@^1.0.0: +modify-values@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== @@ -18282,7 +18522,7 @@ multicast-dns@^6.0.1: dns-packet "^1.3.1" thunky "^1.0.2" -multimatch@^5.0.0: +multimatch@5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz#932b800963cea7a31a033328fa1e0c3a1874dbe6" integrity sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA== @@ -18298,11 +18538,16 @@ mute-stream@0.0.7: resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= -mute-stream@0.0.8, mute-stream@~0.0.4: +mute-stream@0.0.8: version "0.0.8" resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== +mute-stream@^1.0.0, mute-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e" + integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== + nan@^2.12.1: version "2.14.2" resolved "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" @@ -18374,9 +18619,9 @@ needle@^2.5.2: iconv-lite "^0.4.4" sax "^1.2.4" -negotiator@0.6.3: +negotiator@0.6.3, negotiator@^0.6.3: version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.1: @@ -18409,7 +18654,7 @@ node-dir@^0.1.10, node-dir@^0.1.17: dependencies: minimatch "^3.0.2" -node-fetch@^2.6.1: +node-fetch@2.6.7, node-fetch@^2.6.1: version "2.6.7" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== @@ -18428,38 +18673,21 @@ node-forge@^0.10.0: resolved "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== -node-gyp@^5.0.2: - version "5.1.1" - resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.1.tgz#eb915f7b631c937d282e33aed44cb7a025f62a3e" - integrity sha512-WH0WKGi+a4i4DUt2mHnvocex/xPLp9pYt5R6M2JdFB7pJ7Z34hveZ4nDTGTiLXCkitA9T8HFZjhinBCiVHYcWw== - dependencies: - env-paths "^2.2.0" - glob "^7.1.4" - graceful-fs "^4.2.2" - mkdirp "^0.5.1" - nopt "^4.0.1" - npmlog "^4.1.2" - request "^2.88.0" - rimraf "^2.6.3" - semver "^5.7.1" - tar "^4.4.12" - which "^1.3.1" - -node-gyp@^7.1.0: - version "7.1.2" - resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae" - integrity sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ== +node-gyp@^10.0.0: + version "10.1.0" + resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-10.1.0.tgz#75e6f223f2acb4026866c26a2ead6aab75a8ca7e" + integrity sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA== dependencies: env-paths "^2.2.0" - glob "^7.1.4" - graceful-fs "^4.2.3" - nopt "^5.0.0" - npmlog "^4.1.2" - request "^2.88.2" - rimraf "^3.0.2" - semver "^7.3.2" - tar "^6.0.2" - which "^2.0.2" + exponential-backoff "^3.1.1" + glob "^10.3.10" + graceful-fs "^4.2.6" + make-fetch-happen "^13.0.0" + nopt "^7.0.0" + proc-log "^3.0.0" + semver "^7.3.5" + tar "^6.1.2" + which "^4.0.0" node-int64@^0.4.0: version "0.4.0" @@ -18495,6 +18723,11 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" +node-machine-id@1.1.12: + version "1.1.12" + resolved "https://registry.npmjs.org/node-machine-id/-/node-machine-id-1.1.12.tgz#37904eee1e59b320bb9c5d6c0a59f3b469cb6267" + integrity sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ== + node-modules-regexp@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" @@ -18550,20 +18783,12 @@ noms@0.0.0: inherits "^2.0.1" readable-stream "~1.0.31" -nopt@^4.0.1: - version "4.0.3" - resolved "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" - integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== - dependencies: - abbrev "1" - osenv "^0.1.4" - -nopt@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" - integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== +nopt@^7.0.0: + version "7.2.0" + resolved "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz#067378c68116f602f552876194fd11f1292503d7" + integrity sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA== dependencies: - abbrev "1" + abbrev "^2.0.0" nopt@~2.1.1: version "2.1.2" @@ -18572,7 +18797,7 @@ nopt@~2.1.1: dependencies: abbrev "1" -normalize-package-data@^2.0.0, normalize-package-data@^2.3.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0: +normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== @@ -18592,6 +18817,36 @@ normalize-package-data@^3.0.0: semver "^7.3.2" validate-npm-package-license "^3.0.1" +normalize-package-data@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" + integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== + dependencies: + hosted-git-info "^4.0.1" + is-core-module "^2.5.0" + semver "^7.3.4" + validate-npm-package-license "^3.0.1" + +normalize-package-data@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz#abcb8d7e724c40d88462b84982f7cbf6859b4588" + integrity sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q== + dependencies: + hosted-git-info "^6.0.0" + is-core-module "^2.8.1" + semver "^7.3.5" + validate-npm-package-license "^3.0.4" + +normalize-package-data@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz#68a96b3c11edd462af7189c837b6b1064a484196" + integrity sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg== + dependencies: + hosted-git-info "^7.0.0" + is-core-module "^2.8.1" + semver "^7.3.5" + validate-npm-package-license "^3.0.4" + normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" @@ -18624,91 +18879,124 @@ normalize-url@^1.0.0: query-string "^4.1.0" sort-keys "^1.0.0" -normalize-url@^3.3.0: - version "3.3.0" - resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" - integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== - normalize-wheel@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz#aec886affdb045070d856447df62ecf86146ec45" integrity sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU= -npm-bundled@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" - integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA== +npm-bundled@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1" + integrity sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ== dependencies: npm-normalize-package-bin "^1.0.1" -npm-install-checks@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-4.0.0.tgz#a37facc763a2fde0497ef2c6d0ac7c3fbe00d7b4" - integrity sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w== +npm-bundled@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz#7e8e2f8bb26b794265028491be60321a25a39db7" + integrity sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ== dependencies: - semver "^7.1.1" + npm-normalize-package-bin "^3.0.0" -npm-lifecycle@^3.1.5: - version "3.1.5" - resolved "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-3.1.5.tgz#9882d3642b8c82c815782a12e6a1bfeed0026309" - integrity sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g== +npm-install-checks@^6.0.0: + version "6.3.0" + resolved "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz#046552d8920e801fa9f919cad569545d60e826fe" + integrity sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw== dependencies: - byline "^5.0.0" - graceful-fs "^4.1.15" - node-gyp "^5.0.2" - resolve-from "^4.0.0" - slide "^1.1.6" - uid-number "0.0.6" - umask "^1.1.0" - which "^1.3.1" + semver "^7.1.1" -npm-normalize-package-bin@^1.0.0, npm-normalize-package-bin@^1.0.1: +npm-normalize-package-bin@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== -npm-package-arg@^8.0.0, npm-package-arg@^8.0.1, npm-package-arg@^8.1.0, npm-package-arg@^8.1.2: - version "8.1.2" - resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.2.tgz#b868016ae7de5619e729993fbd8d11dc3c52ab62" - integrity sha512-6Eem455JsSMJY6Kpd3EyWE+n5hC+g9bSyHr9K9U2zqZb7+02+hObQ2c0+8iDk/mNF+8r1MhY44WypKJAkySIYA== +npm-normalize-package-bin@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz#25447e32a9a7de1f51362c61a559233b89947832" + integrity sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ== + +npm-package-arg@8.1.1: + version "8.1.1" + resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.1.tgz#00ebf16ac395c63318e67ce66780a06db6df1b04" + integrity sha512-CsP95FhWQDwNqiYS+Q0mZ7FAEDytDZAkNxQqea6IaAFJTAY9Lhhqyl0irU/6PMc7BGfUmnsbHcqxJD7XuVM/rg== dependencies: - hosted-git-info "^4.0.1" - semver "^7.3.4" + hosted-git-info "^3.0.6" + semver "^7.0.0" validate-npm-package-name "^3.0.0" -npm-packlist@^2.1.4: - version "2.1.5" - resolved "https://registry.npmjs.org/npm-packlist/-/npm-packlist-2.1.5.tgz#43ef5bbb9f59b7c0ef91e0905f1dd707b4cfb33c" - integrity sha512-KCfK3Vi2F+PH1klYauoQzg81GQ8/GGjQRKYY6tRnpQUPKTs/1gBZSRWtTEd7jGdSn1LZL7gpAmJT+BcS55k2XQ== +npm-package-arg@^10.0.0, npm-package-arg@^10.1.0: + version "10.1.0" + resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz#827d1260a683806685d17193073cc152d3c7e9b1" + integrity sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA== dependencies: - glob "^7.1.6" - ignore-walk "^3.0.3" - npm-bundled "^1.1.1" - npm-normalize-package-bin "^1.0.1" + hosted-git-info "^6.0.0" + proc-log "^3.0.0" + semver "^7.3.5" + validate-npm-package-name "^5.0.0" -npm-pick-manifest@^6.0.0: - version "6.1.1" - resolved "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz#7b5484ca2c908565f43b7f27644f36bb816f5148" - integrity sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA== +npm-package-arg@^11.0.0: + version "11.0.1" + resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz#f208b0022c29240a1c532a449bdde3f0a4708ebc" + integrity sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ== + dependencies: + hosted-git-info "^7.0.0" + proc-log "^3.0.0" + semver "^7.3.5" + validate-npm-package-name "^5.0.0" + +npm-packlist@5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.1.tgz#79bcaf22a26b6c30aa4dd66b976d69cc286800e0" + integrity sha512-UfpSvQ5YKwctmodvPPkK6Fwk603aoVsf8AEbmVKAEECrfvL8SSe1A2YIwrJ6xmTHAITKPwwZsWo7WwEbNk0kxw== dependencies: - npm-install-checks "^4.0.0" + glob "^8.0.1" + ignore-walk "^5.0.1" + npm-bundled "^1.1.2" npm-normalize-package-bin "^1.0.1" - npm-package-arg "^8.1.2" - semver "^7.3.4" -npm-registry-fetch@^9.0.0: +npm-packlist@^8.0.0: + version "8.0.2" + resolved "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz#5b8d1d906d96d21c85ebbeed2cf54147477c8478" + integrity sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA== + dependencies: + ignore-walk "^6.0.4" + +npm-pick-manifest@^9.0.0: version "9.0.0" - resolved "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-9.0.0.tgz#86f3feb4ce00313bc0b8f1f8f69daae6face1661" - integrity sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA== + resolved "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.0.tgz#f87a4c134504a2c7931f2bb8733126e3c3bb7e8f" + integrity sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg== dependencies: - "@npmcli/ci-detect" "^1.0.0" - lru-cache "^6.0.0" - make-fetch-happen "^8.0.9" - minipass "^3.1.3" - minipass-fetch "^1.3.0" + npm-install-checks "^6.0.0" + npm-normalize-package-bin "^3.0.0" + npm-package-arg "^11.0.0" + semver "^7.3.5" + +npm-registry-fetch@^14.0.3, npm-registry-fetch@^14.0.5: + version "14.0.5" + resolved "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz#fe7169957ba4986a4853a650278ee02e568d115d" + integrity sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA== + dependencies: + make-fetch-happen "^11.0.0" + minipass "^5.0.0" + minipass-fetch "^3.0.0" + minipass-json-stream "^1.0.1" + minizlib "^2.1.2" + npm-package-arg "^10.0.0" + proc-log "^3.0.0" + +npm-registry-fetch@^16.0.0: + version "16.2.0" + resolved "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.2.0.tgz#f9302e0a0e0e47138c29b5d801ea928f6f6edb8b" + integrity sha512-zVH+G0q1O2hqgQBUvQ2LWp6ujr6VJAeDnmWxqiMlCguvLexEzBnuQIwC70r04vcvCMAcYEIpA/rO9YyVi+fmJQ== + dependencies: + "@npmcli/redact" "^1.1.0" + make-fetch-happen "^13.0.0" + minipass "^7.0.2" + minipass-fetch "^3.0.0" minipass-json-stream "^1.0.1" - minizlib "^2.0.0" - npm-package-arg "^8.0.0" + minizlib "^2.1.2" + npm-package-arg "^11.0.0" + proc-log "^3.0.0" npm-run-all@^4.1.5: version "4.1.5" @@ -18739,15 +19027,12 @@ npm-run-path@^4.0.0, npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" -npmlog@^4.1.2: - version "4.1.2" - resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== +npm-run-path@^5.1.0: + version "5.3.0" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f" + integrity sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ== dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" + path-key "^4.0.0" npmlog@^5.0.1: version "5.0.1" @@ -18759,6 +19044,16 @@ npmlog@^5.0.1: gauge "^3.0.0" set-blocking "^2.0.0" +npmlog@^6.0.2: + version "6.0.2" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830" + integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg== + dependencies: + are-we-there-yet "^3.0.0" + console-control-strings "^1.1.0" + gauge "^4.0.3" + set-blocking "^2.0.0" + nth-check@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" @@ -18801,6 +19096,57 @@ nwsapi@^2.2.2: resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz#e5418863e7905df67d51ec95938d67bf801f0bb0" integrity sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw== +nx@18.2.3, "nx@>=17.1.2 < 19": + version "18.2.3" + resolved "https://registry.npmjs.org/nx/-/nx-18.2.3.tgz#40d4c18a3b7143e10b3645b5bd47a65c5b9d5e6f" + integrity sha512-4XGvvIzXeeeSj1hObiBL7E7aXX6rbiB1F856AqUdGoysYfkhcxOFyeAv5XsXeukl9gYwh/LH84paXjEOkGaJlA== + dependencies: + "@nrwl/tao" "18.2.3" + "@yarnpkg/lockfile" "^1.1.0" + "@yarnpkg/parsers" "3.0.0-rc.46" + "@zkochan/js-yaml" "0.0.6" + axios "^1.6.0" + chalk "^4.1.0" + cli-cursor "3.1.0" + cli-spinners "2.6.1" + cliui "^8.0.1" + dotenv "~16.3.1" + dotenv-expand "~10.0.0" + enquirer "~2.3.6" + figures "3.2.0" + flat "^5.0.2" + fs-extra "^11.1.0" + ignore "^5.0.4" + jest-diff "^29.4.1" + js-yaml "4.1.0" + jsonc-parser "3.2.0" + lines-and-columns "~2.0.3" + minimatch "9.0.3" + node-machine-id "1.1.12" + npm-run-path "^4.0.1" + open "^8.4.0" + ora "5.3.0" + semver "^7.5.3" + string-width "^4.2.3" + strong-log-transformer "^2.1.0" + tar-stream "~2.2.0" + tmp "~0.2.1" + tsconfig-paths "^4.1.2" + tslib "^2.3.0" + yargs "^17.6.2" + yargs-parser "21.1.1" + optionalDependencies: + "@nx/nx-darwin-arm64" "18.2.3" + "@nx/nx-darwin-x64" "18.2.3" + "@nx/nx-freebsd-x64" "18.2.3" + "@nx/nx-linux-arm-gnueabihf" "18.2.3" + "@nx/nx-linux-arm64-gnu" "18.2.3" + "@nx/nx-linux-arm64-musl" "18.2.3" + "@nx/nx-linux-x64-gnu" "18.2.3" + "@nx/nx-linux-x64-musl" "18.2.3" + "@nx/nx-win32-arm64-msvc" "18.2.3" + "@nx/nx-win32-x64-msvc" "18.2.3" + oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" @@ -18963,6 +19309,13 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + only@~0.0.2: version "0.0.2" resolved "https://registry.npmjs.org/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" @@ -18976,6 +19329,15 @@ open@^7.0.2, open@^7.0.3: is-docker "^2.0.0" is-wsl "^2.1.1" +open@^8.4.0: + version "8.4.2" + resolved "https://registry.npmjs.org/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" + integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + opn@^5.5.0: version "5.5.0" resolved "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" @@ -19007,6 +19369,20 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" +ora@5.3.0: + version "5.3.0" + resolved "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz#fb832899d3a1372fe71c8b2c534bbfe74961bb6f" + integrity sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g== + dependencies: + bl "^4.0.3" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.5.0" + is-interactive "^1.0.0" + log-symbols "^4.0.0" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + ora@^4.0.2: version "4.1.1" resolved "https://registry.npmjs.org/ora/-/ora-4.1.1.tgz#566cc0348a15c36f5f0e979612842e02ba9dddbc" @@ -19048,11 +19424,6 @@ os-browserify@^0.3.0: resolved "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= - os-locale@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" @@ -19062,19 +19433,11 @@ os-locale@^3.0.0: lcid "^2.0.0" mem "^4.0.0" -os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: +os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -osenv@^0.1.4: - version "0.1.5" - resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" - integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - output-file-sync@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/output-file-sync/-/output-file-sync-2.0.1.tgz#f53118282f5f553c2799541792b723a4c71430c0" @@ -19163,6 +19526,13 @@ p-limit@^3.0.2, p-limit@^3.1.0: dependencies: yocto-queue "^0.1.0" +p-limit@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz#914af6544ed32bfa54670b061cafcbd04984b644" + integrity sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ== + dependencies: + yocto-queue "^1.0.0" + p-locate@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -19191,11 +19561,25 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" -p-map-series@^2.1.0: +p-locate@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz#3da9a49d4934b901089dca3302fa65dc5a05c04f" + integrity sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw== + dependencies: + p-limit "^4.0.0" + +p-map-series@2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/p-map-series/-/p-map-series-2.1.0.tgz#7560d4c452d9da0c07e692fdbfe6e2c81a2a91f2" integrity sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q== +p-map@4.0.0, p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + p-map@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" @@ -19208,19 +19592,12 @@ p-map@^3.0.0: dependencies: aggregate-error "^3.0.0" -p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== - dependencies: - aggregate-error "^3.0.0" - -p-pipe@^3.1.0: +p-pipe@3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/p-pipe/-/p-pipe-3.1.0.tgz#48b57c922aa2e1af6a6404cb7c6bf0eb9cc8e60e" integrity sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw== -p-queue@^6.6.2: +p-queue@6.6.2: version "6.6.2" resolved "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426" integrity sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ== @@ -19228,16 +19605,16 @@ p-queue@^6.6.2: eventemitter3 "^4.0.4" p-timeout "^3.2.0" +p-reduce@2.1.0, p-reduce@^2.0.0, p-reduce@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" + integrity sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw== + p-reduce@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= -p-reduce@^2.0.0, p-reduce@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" - integrity sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw== - p-retry@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328" @@ -19262,37 +19639,36 @@ p-try@^2.0.0: resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -p-waterfall@^2.1.1: +p-waterfall@2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/p-waterfall/-/p-waterfall-2.1.1.tgz#63153a774f472ccdc4eb281cdb2967fcf158b2ee" integrity sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw== dependencies: p-reduce "^2.0.0" -pacote@^11.2.6: - version "11.3.1" - resolved "https://registry.npmjs.org/pacote/-/pacote-11.3.1.tgz#6ce95dd230db475cbd8789fd1f986bec51b4bf7c" - integrity sha512-TymtwoAG12cczsJIrwI/euOQKtjrQHlD0k0oyt9QSmZGpqa+KdlxKdWR/YUjYizkixaVyztxt/Wsfo8bL3A6Fg== - dependencies: - "@npmcli/git" "^2.0.1" - "@npmcli/installed-package-contents" "^1.0.6" - "@npmcli/promise-spawn" "^1.2.0" - "@npmcli/run-script" "^1.8.2" - cacache "^15.0.5" - chownr "^2.0.0" - fs-minipass "^2.1.0" - infer-owner "^1.0.4" - minipass "^3.1.3" - mkdirp "^1.0.3" - npm-package-arg "^8.0.1" - npm-packlist "^2.1.4" - npm-pick-manifest "^6.0.0" - npm-registry-fetch "^9.0.0" +pacote@^17.0.5: + version "17.0.6" + resolved "https://registry.npmjs.org/pacote/-/pacote-17.0.6.tgz#874bb59cda5d44ab784d0b6530fcb4a7d9b76a60" + integrity sha512-cJKrW21VRE8vVTRskJo78c/RCvwJCn1f4qgfxL4w77SOWrTCRcmfkYHlHtS0gqpgjv3zhXflRtgsrUCX5xwNnQ== + dependencies: + "@npmcli/git" "^5.0.0" + "@npmcli/installed-package-contents" "^2.0.1" + "@npmcli/promise-spawn" "^7.0.0" + "@npmcli/run-script" "^7.0.0" + cacache "^18.0.0" + fs-minipass "^3.0.0" + minipass "^7.0.2" + npm-package-arg "^11.0.0" + npm-packlist "^8.0.0" + npm-pick-manifest "^9.0.0" + npm-registry-fetch "^16.0.0" + proc-log "^3.0.0" promise-retry "^2.0.1" - read-package-json-fast "^2.0.1" - rimraf "^3.0.2" - ssri "^8.0.1" - tar "^6.1.0" + read-package-json "^7.0.0" + read-package-json-fast "^3.0.0" + sigstore "^2.2.0" + ssri "^10.0.0" + tar "^6.1.11" pako@~1.0.2, pako@~1.0.5: version "1.0.11" @@ -19346,11 +19722,6 @@ parse-entities@^2.0.0: is-decimal "^1.0.0" is-hexadecimal "^1.0.0" -parse-github-repo-url@^1.3.0: - version "1.4.1" - resolved "https://registry.npmjs.org/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz#9e7d8bb252a6cb6ba42595060b7bf6df3dbc1f50" - integrity sha1-nn2LslKmy2ukJZUGC3v23z28H1A= - parse-json@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" @@ -19366,7 +19737,7 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" -parse-json@^5.0.0: +parse-json@^5.0.0, parse-json@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -19386,25 +19757,19 @@ parse-passwd@^1.0.0: resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= -parse-path@^4.0.0: - version "4.0.3" - resolved "https://registry.npmjs.org/parse-path/-/parse-path-4.0.3.tgz#82d81ec3e071dcc4ab49aa9f2c9c0b8966bb22bf" - integrity sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA== +parse-path@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/parse-path/-/parse-path-7.0.0.tgz#605a2d58d0a749c8594405d8cc3a2bf76d16099b" + integrity sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog== dependencies: - is-ssh "^1.3.0" - protocols "^1.4.0" - qs "^6.9.4" - query-string "^6.13.8" + protocols "^2.0.0" -parse-url@^5.0.0: - version "5.0.2" - resolved "https://registry.npmjs.org/parse-url/-/parse-url-5.0.2.tgz#856a3be1fcdf78dc93fc8b3791f169072d898b59" - integrity sha512-Czj+GIit4cdWtxo3ISZCvLiUjErSo0iI3wJ+q9Oi3QuMYTI6OZu+7cewMWZ+C1YAnKhYTk6/TLuhIgCypLthPA== +parse-url@^8.1.0: + version "8.1.0" + resolved "https://registry.npmjs.org/parse-url/-/parse-url-8.1.0.tgz#972e0827ed4b57fc85f0ea6b0d839f0d8a57a57d" + integrity sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w== dependencies: - is-ssh "^1.3.0" - normalize-url "^3.3.0" - parse-path "^4.0.0" - protocols "^1.4.0" + parse-path "^7.0.0" parse5-htmlparser2-tree-adapter@^6.0.0: version "6.0.1" @@ -19463,13 +19828,6 @@ path-dirname@^1.0.0: resolved "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= -path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= - dependencies: - pinkie-promise "^2.0.0" - path-exists@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -19480,6 +19838,11 @@ path-exists@^4.0.0: resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== +path-exists@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz#a6aad9489200b21fab31e49cf09277e5116fb9e7" + integrity sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ== + path-is-absolute@1.0.1, path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -19507,11 +19870,24 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + path-parse@^1.0.6: version "1.0.7" resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^1.10.2, path-scurry@^1.6.1: + version "1.10.2" + resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz#8f6357eb1239d5fa1da8b9f70e9c080675458ba7" + integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-strip-sep@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/path-strip-sep/-/path-strip-sep-1.0.7.tgz#51f31fd53099b7ba59876b7b9e6492397441223d" @@ -19536,15 +19912,6 @@ path-to-regexp@^1.7.0: dependencies: isarray "0.0.1" -path-type@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= - dependencies: - graceful-fs "^4.1.2" - pify "^2.0.0" - pinkie-promise "^2.0.0" - path-type@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" @@ -19620,6 +19987,11 @@ pidtree@^0.3.0: resolved "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== +pify@5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" + integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== + pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -19635,11 +20007,6 @@ pify@^4.0.1: resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pify@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" - integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== - pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" @@ -19909,10 +20276,10 @@ prepend-http@^1.0.0: resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= -prettier@2.3.2: - version "2.3.2" - resolved "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d" - integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ== +prettier@3.2.5: + version "3.2.5" + resolved "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" + integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== "prettier@>=2.2.1 <=2.3.0": version "2.3.0" @@ -19976,6 +20343,15 @@ pretty-format@^27.0.2, pretty-format@^27.4.6: ansi-styles "^5.0.0" react-is "^17.0.1" +pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + pretty-hrtime@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" @@ -19998,6 +20374,11 @@ private@^0.1.8, private@~0.1.5: resolved "https://registry.npmjs.org/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== +proc-log@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz#fb05ef83ccd64fd7b20bbe9c8c1070fc08338dd8" + integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A== + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -20063,12 +20444,12 @@ prompts@^2.0.1, prompts@^2.4.0: kleur "^3.0.3" sisteransi "^1.0.5" -promzard@^0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" - integrity sha1-JqXW7ox97kyxIggwWs+5O6OCqe4= +promzard@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/promzard/-/promzard-1.0.1.tgz#3b77251a24f988c0886f5649d4f642bcdd53e558" + integrity sha512-ulDF77aULEHUoJkN5XZgRV5loHXBaqd9eorMvLNLvi2gXMuRAtwH6Gh4zsMHQY1kTt7tyv/YZwZW5C2gtj8F2A== dependencies: - read "1" + read "^3.0.1" prop-types@^15.0.0, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" @@ -20104,15 +20485,10 @@ property-information@^5.0.0, property-information@^5.3.0: dependencies: xtend "^4.0.0" -proto-list@~1.2.1: - version "1.2.4" - resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" - integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= - -protocols@^1.1.0, protocols@^1.4.0: - version "1.4.8" - resolved "https://registry.npmjs.org/protocols/-/protocols-1.4.8.tgz#48eea2d8f58d9644a4a32caae5d5db290a075ce8" - integrity sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg== +protocols@^2.0.0, protocols@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86" + integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q== proxy-addr@~2.0.7: version "2.0.7" @@ -20122,7 +20498,7 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" -proxy-from-env@^1.0.0: +proxy-from-env@^1.0.0, proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== @@ -20219,12 +20595,7 @@ q-i@^2.0.1: is-plain-object "^2.0.4" stringify-object "^3.2.0" -q@^1.5.1: - version "1.5.1" - resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= - -qs@6.11.0, qs@^6.10.0, qs@^6.11.0, qs@^6.5.2, qs@^6.9.4: +qs@6.11.0, qs@^6.10.0, qs@^6.11.0, qs@^6.5.2: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== @@ -20249,16 +20620,6 @@ query-string@^4.1.0: object-assign "^4.1.0" strict-uri-encode "^1.0.0" -query-string@^6.13.8: - version "6.14.1" - resolved "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz#7ac2dca46da7f309449ba0f86b1fd28255b0c86a" - integrity sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw== - dependencies: - decode-uri-component "^0.2.0" - filter-obj "^1.1.0" - split-on-first "^1.0.0" - strict-uri-encode "^2.0.0" - querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -20584,6 +20945,11 @@ react-is@^17.0.1: resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" @@ -20875,60 +21241,43 @@ react-transition-group@^4.4.2: react@17.0.2, react@^17.0.2: version "17.0.2" resolved "https://registry.npmjs.org/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - -read-cmd-shim@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-2.0.0.tgz#4a50a71d6f0965364938e9038476f7eede3928d9" - integrity sha512-HJpV9bQpkl6KwjxlJcBoqu9Ba0PQg8TqSNIOrulGt54a0uup0HtevreFHzYzkm0lpnleRdNBzXznKrgxglEHQw== - -read-package-json-fast@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.2.tgz#2dcb24d9e8dd50fb322042c8c35a954e6cc7ac9e" - integrity sha512-5fyFUyO9B799foVk4n6ylcoAktG/FbE3jwRKxvwaeSrIunaoMc0u81dzXxjeAFKOce7O5KncdfwpGvvs6r5PsQ== + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== dependencies: - json-parse-even-better-errors "^2.3.0" - npm-normalize-package-bin "^1.0.1" + loose-envify "^1.1.0" + object-assign "^4.1.1" -read-package-json@^2.0.0: - version "2.1.2" - resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz#6992b2b66c7177259feb8eaac73c3acd28b9222a" - integrity sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA== - dependencies: - glob "^7.1.1" - json-parse-even-better-errors "^2.3.0" - normalize-package-data "^2.0.0" - npm-normalize-package-bin "^1.0.0" +read-cmd-shim@4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz#640a08b473a49043e394ae0c7a34dd822c73b9bb" + integrity sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q== -read-package-json@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-3.0.1.tgz#c7108f0b9390257b08c21e3004d2404c806744b9" - integrity sha512-aLcPqxovhJTVJcsnROuuzQvv6oziQx4zd3JvG0vGCL5MjTONUc4uJ90zCBC6R7W7oUKBNoR/F8pkyfVwlbxqng== +read-package-json-fast@^3.0.0: + version "3.0.2" + resolved "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz#394908a9725dc7a5f14e70c8e7556dff1d2b1049" + integrity sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw== dependencies: - glob "^7.1.1" - json-parse-even-better-errors "^2.3.0" - normalize-package-data "^3.0.0" - npm-normalize-package-bin "^1.0.0" + json-parse-even-better-errors "^3.0.0" + npm-normalize-package-bin "^3.0.0" -read-package-tree@^5.3.1: - version "5.3.1" - resolved "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz#a32cb64c7f31eb8a6f31ef06f9cedf74068fe636" - integrity sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw== +read-package-json@6.0.4, read-package-json@^6.0.0: + version "6.0.4" + resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.4.tgz#90318824ec456c287437ea79595f4c2854708836" + integrity sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw== dependencies: - read-package-json "^2.0.0" - readdir-scoped-modules "^1.0.0" - util-promisify "^2.1.0" + glob "^10.2.2" + json-parse-even-better-errors "^3.0.0" + normalize-package-data "^5.0.0" + npm-normalize-package-bin "^3.0.0" -read-pkg-up@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= +read-package-json@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.0.tgz#d605c9dcf6bc5856da24204aa4e9518ee9714be0" + integrity sha512-uL4Z10OKV4p6vbdvIXB+OzhInYtIozl/VxUBPgNkBuUi2DeRonnuspmaVAMcrkmfjKGNmRndyQAbE7/AmzGwFg== dependencies: - find-up "^1.0.0" - read-pkg "^1.0.0" + glob "^10.2.2" + json-parse-even-better-errors "^3.0.0" + normalize-package-data "^6.0.0" + npm-normalize-package-bin "^3.0.0" read-pkg-up@^2.0.0: version "2.0.0" @@ -20963,15 +21312,6 @@ read-pkg-up@^7.0.1: read-pkg "^5.2.0" type-fest "^0.8.1" -read-pkg@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= - dependencies: - load-json-file "^1.0.0" - normalize-package-data "^2.3.2" - path-type "^1.0.0" - read-pkg@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" @@ -21000,14 +21340,21 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -read@1, read@~1.0.1: - version "1.0.7" - resolved "https://registry.npmjs.org/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" - integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= +read@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/read/-/read-2.1.0.tgz#69409372c54fe3381092bc363a00650b6ac37218" + integrity sha512-bvxi1QLJHcaywCAEsAk4DG3nVoqiY2Csps3qzWalhj5hFqRn1d/OixkFXtLO1PrgHUcAP0FNaSY/5GYNfENFFQ== + dependencies: + mute-stream "~1.0.0" + +read@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/read/-/read-3.0.1.tgz#926808f0f7c83fa95f1ef33c0e2c09dbb28fd192" + integrity sha512-SLBrDU/Srs/9EoWhU5GdbAoxG1GzpQHo/6qiGItaoLJ1thmYpcNIM1qISEUvyHBzfGlWIyd6p2DNi1oV1VmAuw== dependencies: - mute-stream "~0.0.4" + mute-stream "^1.0.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -21020,7 +21367,7 @@ read@1, read@~1.0.1: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0: +readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -21048,16 +21395,6 @@ readable-stream@~1.0.31: isarray "0.0.1" string_decoder "~0.10.x" -readdir-scoped-modules@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309" - integrity sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw== - dependencies: - debuglog "^1.0.1" - dezalgo "^1.0.0" - graceful-fs "^4.1.2" - once "^1.3.0" - readdirp@^2.2.1: version "2.2.1" resolved "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" @@ -21127,14 +21464,6 @@ recursive-readdir@2.2.2: dependencies: minimatch "3.0.4" -redent@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" - integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= - dependencies: - indent-string "^2.1.0" - strip-indent "^1.0.1" - redent@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" @@ -21418,13 +21747,6 @@ repeat-string@^1.0.0, repeat-string@^1.5.4, repeat-string@^1.6.1: resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= - dependencies: - is-finite "^1.0.0" - request-promise-core@1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f" @@ -21534,7 +21856,7 @@ resolve-from@^4.0.0: resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve-global@1.0.0, resolve-global@^1.0.0: +resolve-global@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz#a2a79df4af2ca3f49bf77ef9ddacd322dad19255" integrity sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw== @@ -21630,6 +21952,13 @@ rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" +rimraf@^4.4.1: + version "4.4.1" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz#bd33364f67021c5b79e93d7f4fa0568c7c21b755" + integrity sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og== + dependencies: + glob "^9.2.0" + rimraf@~2.6.2: version "2.6.3" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" @@ -21696,7 +22025,7 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -rxjs@^6.4.0, rxjs@^6.5.5, rxjs@^6.6.0: +rxjs@^6.4.0, rxjs@^6.5.5: version "6.6.6" resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.6.tgz#14d8417aa5a07c5e633995b525e1e3c0dec03b70" integrity sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg== @@ -21710,6 +22039,13 @@ rxjs@^7.1.0: dependencies: tslib "~2.1.0" +rxjs@^7.5.5: + version "7.8.1" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" + safe-buffer@5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" @@ -21867,7 +22203,7 @@ selfsigned@^1.10.7, selfsigned@^1.10.8: dependencies: node-forge "^0.10.0" -"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: +"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: version "5.7.1" resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -21889,7 +22225,14 @@ semver@7.3.5: dependencies: lru-cache "^6.0.0" -semver@^7.1.1, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7: +semver@^7.0.0, semver@^7.3.8, semver@^7.5.3, semver@^7.6.0: + version "7.6.0" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" + integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== + dependencies: + lru-cache "^6.0.0" + +semver@^7.1.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7: version "7.5.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.2.tgz#5b851e66d1be07c1cdaf37dfc856f543325a2beb" integrity sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ== @@ -22014,7 +22357,7 @@ serve@^13.0.2: serve-handler "6.1.3" update-check "1.5.2" -set-blocking@^2.0.0, set-blocking@~2.0.0: +set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= @@ -22116,26 +22459,59 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" +signal-exit@3.0.7, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== +signal-exit@^4.0.1, signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +sigstore@^1.4.0: + version "1.9.0" + resolved "https://registry.npmjs.org/sigstore/-/sigstore-1.9.0.tgz#1e7ad8933aa99b75c6898ddd0eeebc3eb0d59875" + integrity sha512-0Zjz0oe37d08VeOtBIuB6cRriqXse2e8w+7yIy2XSXjshRKxbc2KkhXjL229jXSxEm7UbcjS76wcJDGQddVI9A== + dependencies: + "@sigstore/bundle" "^1.1.0" + "@sigstore/protobuf-specs" "^0.2.0" + "@sigstore/sign" "^1.0.0" + "@sigstore/tuf" "^1.0.3" + make-fetch-happen "^11.0.1" + +sigstore@^2.2.0: + version "2.3.0" + resolved "https://registry.npmjs.org/sigstore/-/sigstore-2.3.0.tgz#c56b32818d4dc989f6ea3c0897f4d9bff5d14bed" + integrity sha512-q+o8L2ebiWD1AxD17eglf1pFrl9jtW7FHa0ygqY6EKvibK8JHyq9Z26v9MZXeDiw+RbfOJ9j2v70M10Hd6E06A== + dependencies: + "@sigstore/bundle" "^2.3.1" + "@sigstore/core" "^1.0.0" + "@sigstore/protobuf-specs" "^0.3.1" + "@sigstore/sign" "^2.3.0" + "@sigstore/tuf" "^2.3.1" + "@sigstore/verify" "^1.2.0" + sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== +slash@3.0.0, slash@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + slash@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - slice-ansi@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" @@ -22145,15 +22521,10 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -slide@^1.1.6: - version "1.1.6" - resolved "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" - integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= - -smart-buffer@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz#91605c25d91652f4661ea69ccf45f1b331ca21ba" - integrity sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw== +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== smoothscroll-polyfill@^0.4.4: version "0.4.4" @@ -22231,22 +22602,31 @@ sockjs@^0.3.21: uuid "^3.4.0" websocket-driver "^0.7.4" -socks-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.0.tgz#7c0f364e7b1cf4a7a437e71253bed72e9004be60" - integrity sha512-lEpa1zsWCChxiynk+lCycKuC502RxDWLKJZoIhnxrWNjLSDGYRFflHA1/228VkRcnv9TIb8w98derGbpKxJRgA== +socks-proxy-agent@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz#dc069ecf34436621acb41e3efa66ca1b5fed15b6" + integrity sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww== dependencies: - agent-base "6" - debug "4" - socks "^2.3.3" + agent-base "^6.0.2" + debug "^4.3.3" + socks "^2.6.2" -socks@^2.3.3: - version "2.6.0" - resolved "https://registry.npmjs.org/socks/-/socks-2.6.0.tgz#6b984928461d39871b3666754b9000ecf39dfac2" - integrity sha512-mNmr9owlinMplev0Wd7UHFlqI4ofnBnNzFuzrm63PPaHgbkqCFe4T5LzwKmtQ/f2tX0NTpcdVLyD/FHxFBstYw== +socks-proxy-agent@^8.0.3: + version "8.0.3" + resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz#6b2da3d77364fde6292e810b496cb70440b9b89d" + integrity sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A== dependencies: - ip "^1.1.5" - smart-buffer "^4.1.0" + agent-base "^7.1.1" + debug "^4.3.4" + socks "^2.7.1" + +socks@^2.6.2, socks@^2.7.1: + version "2.8.1" + resolved "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz#22c7d9dd7882649043cba0eafb49ae144e3457af" + integrity sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ== + dependencies: + ip-address "^9.0.5" + smart-buffer "^4.2.0" sort-keys@^1.0.0: version "1.1.2" @@ -22262,13 +22642,6 @@ sort-keys@^2.0.0: dependencies: is-plain-obj "^1.0.0" -sort-keys@^4.0.0: - version "4.2.0" - resolved "https://registry.npmjs.org/sort-keys/-/sort-keys-4.2.0.tgz#6b7638cee42c506fff8c1cecde7376d21315be18" - integrity sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg== - dependencies: - is-plain-obj "^2.0.0" - source-list-map@^2.0.0, source-list-map@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" @@ -22405,11 +22778,6 @@ split-ca@^1.0.1: resolved "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz#6c83aff3692fa61256e0cd197e05e9de157691a6" integrity sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ== -split-on-first@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" - integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== - split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" @@ -22417,20 +22785,30 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" -split2@^3.0.0: +split2@^3.2.2: version "3.2.2" resolved "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== dependencies: readable-stream "^3.0.0" -split@^1.0.0: +split2@^4.0.0: + version "4.2.0" + resolved "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== + +split@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== dependencies: through "2" +sprintf-js@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" + integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -22462,6 +22840,13 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" +ssri@^10.0.0, ssri@^10.0.1: + version "10.0.5" + resolved "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz#e49efcd6e36385196cb515d3a2ad6c3f0265ef8c" + integrity sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A== + dependencies: + minipass "^7.0.3" + ssri@^6.0.1: version "6.0.2" resolved "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5" @@ -22469,13 +22854,20 @@ ssri@^6.0.1: dependencies: figgy-pudding "^3.5.1" -ssri@^8.0.0, ssri@^8.0.1: +ssri@^8.0.0: version "8.0.1" resolved "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== dependencies: minipass "^3.1.1" +ssri@^9.0.1: + version "9.0.1" + resolved "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz#544d4c357a8d7b71a19700074b6883fcb4eae057" + integrity sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q== + dependencies: + minipass "^3.1.1" + stable@^0.1.8: version "0.1.8" resolved "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" @@ -22570,11 +22962,6 @@ strict-uri-encode@^1.0.0: resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= -strict-uri-encode@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" - integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= - string-length@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" @@ -22607,6 +22994,15 @@ string-replace-loader@^3.0.1: loader-utils "^2.0.0" schema-utils "^3.0.0" +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -22616,14 +23012,6 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -22633,6 +23021,14 @@ string-width@^1.0.1: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + string-width@^3.0.0, string-width@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" @@ -22651,6 +23047,15 @@ string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2 is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + "string.prototype.matchall@^4.0.0 || ^3.0.1", string.prototype.matchall@^4.0.4: version "4.0.4" resolved "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.4.tgz#608f255e93e072107f5de066f81a2dfb78cf6b29" @@ -22735,6 +23140,13 @@ stringify-object@^3.2.0: is-obj "^1.0.1" is-regexp "^1.0.0" +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@6.0.0, strip-ansi@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" @@ -22770,18 +23182,18 @@ strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + strip-bom@4.0.0, strip-bom@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== -strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= - dependencies: - is-utf8 "^0.2.0" - strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -22797,18 +23209,16 @@ strip-final-newline@^2.0.0: resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + strip-html-comments@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/strip-html-comments/-/strip-html-comments-1.0.0.tgz#0ae7dff0300a6075a4c293fb6111b4cb1d0cb7b7" integrity sha1-Cuff8DAKYHWkwpP7YRG0yx0Mt7c= -strip-indent@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" - integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= - dependencies: - get-stdin "^4.0.1" - strip-indent@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" @@ -22843,7 +23253,7 @@ strip-url-auth@^1.0.0: resolved "https://registry.npmjs.org/strip-url-auth/-/strip-url-auth-1.0.1.tgz#22b0fa3a41385b33be3f331551bbb837fa0cd7ae" integrity sha1-IrD6OkE4WzO+PzMVUbu4N/oM164= -strong-log-transformer@^2.1.0: +strong-log-transformer@2.1.0, strong-log-transformer@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz#0f5ed78d325e0421ac6f90f7f10e691d6ae3ae10" integrity sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA== @@ -23070,7 +23480,7 @@ tar-fs@~2.0.1: pump "^3.0.0" tar-stream "^2.0.0" -tar-stream@^2.0.0: +tar-stream@^2.0.0, tar-stream@~2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== @@ -23081,20 +23491,19 @@ tar-stream@^2.0.0: inherits "^2.0.3" readable-stream "^3.1.1" -tar@^4.4.12: - version "4.4.19" - resolved "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" - integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA== +tar@6.1.11: + version "6.1.11" + resolved "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== dependencies: - chownr "^1.1.4" - fs-minipass "^1.2.7" - minipass "^2.9.0" - minizlib "^1.3.3" - mkdirp "^0.5.5" - safe-buffer "^5.2.1" - yallist "^3.1.1" + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^3.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" -tar@^6.0.2, tar@^6.1.0: +tar@^6.0.2: version "6.1.0" resolved "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz#d1724e9bcc04b977b18d5c573b333a2207229a83" integrity sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA== @@ -23106,6 +23515,18 @@ tar@^6.0.2, tar@^6.1.0: mkdirp "^1.0.3" yallist "^4.0.0" +tar@^6.1.11, tar@^6.1.2: + version "6.2.1" + resolved "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^5.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + telejson@^5.3.2, telejson@^5.3.3: version "5.3.3" resolved "https://registry.npmjs.org/telejson/-/telejson-5.3.3.tgz#fa8ca84543e336576d8734123876a9f02bf41d2e" @@ -23134,21 +23555,10 @@ telejson@^6.0.8: lodash "^4.17.21" memoizerific "^1.11.3" -temp-dir@^1.0.0: +temp-dir@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" - integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0= - -temp-write@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/temp-write/-/temp-write-4.0.0.tgz#cd2e0825fc826ae72d201dc26eef3bf7e6fc9320" - integrity sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw== - dependencies: - graceful-fs "^4.1.15" - is-stream "^2.0.0" - make-dir "^3.0.0" - temp-dir "^1.0.0" - uuid "^3.3.2" + integrity sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ== temp@^0.8.1: version "0.8.4" @@ -23244,6 +23654,11 @@ text-extensions@^1.0.0: resolved "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== +text-extensions@^2.0.0: + version "2.4.0" + resolved "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz#a1cfcc50cf34da41bfd047cc744f804d1680ea34" + integrity sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g== + text-table@0.2.0, text-table@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -23277,13 +23692,6 @@ through2@^2.0.0, through2@^2.0.1: readable-stream "~2.3.6" xtend "~4.0.1" -through2@^4.0.0: - version "4.0.2" - resolved "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" - integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== - dependencies: - readable-stream "3" - through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6: version "2.3.8" resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -23337,6 +23745,11 @@ tmp@^0.2.1: dependencies: rimraf "^3.0.0" +tmp@~0.2.1: + version "0.2.3" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" + integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== + tmpl@1.0.x: version "1.0.5" resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" @@ -23464,21 +23877,11 @@ tr46@~0.0.3: resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= -trim-newlines@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" - integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= - trim-newlines@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz#79726304a6a898aa8373427298d54c2ee8b1cb30" integrity sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA== -trim-off-newlines@^1.0.0: - version "1.0.3" - resolved "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.3.tgz#8df24847fcb821b0ab27d58ab6efec9f2fe961a1" - integrity sha512-kh6Tu6GbeSNMGfrrZh6Bb/4ZEHV1QlB4xNDBeog8Y9/QwFlKTRyWvY3Fs9tRDAMZliVUwieMgEdIeL/FtqjkJg== - trim-repeated@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" @@ -23559,6 +23962,15 @@ tsconfig-paths@^4.0.0: minimist "^1.2.6" strip-bom "^3.0.0" +tsconfig-paths@^4.1.2: + version "4.2.0" + resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c" + integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg== + dependencies: + json5 "^2.2.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + tslib@2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" @@ -23584,6 +23996,11 @@ tslib@^2.0.1, tslib@^2.0.3, tslib@~2.1.0: resolved "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== +tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0: + version "2.6.2" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + tsscmp@1.0.6: version "1.0.6" resolved "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" @@ -23608,6 +24025,24 @@ tty-browserify@0.0.0: resolved "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= +tuf-js@^1.1.7: + version "1.1.7" + resolved "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz#21b7ae92a9373015be77dfe0cb282a80ec3bbe43" + integrity sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg== + dependencies: + "@tufjs/models" "1.0.4" + debug "^4.3.4" + make-fetch-happen "^11.1.1" + +tuf-js@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.0.tgz#4daaa8620ba7545501d04dfa933c98abbcc959b9" + integrity sha512-ZSDngmP1z6zw+FIkIBjvOp/II/mIub/O7Pp12j1WNsiCpg5R5wAc//i555bBQsE44O94btLt0xM/Zr2LQjwdCg== + dependencies: + "@tufjs/models" "2.0.0" + debug "^4.3.4" + make-fetch-happen "^13.0.0" + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -23699,21 +24134,16 @@ typescript@4.5.4: resolved "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8" integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg== +"typescript@>=3 < 6": + version "5.4.4" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz#eb2471e7b0a5f1377523700a21669dce30c2d952" + integrity sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw== + uglify-js@^3.1.4: version "3.12.8" resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.12.8.tgz#a82e6e53c9be14f7382de3d068ef1e26e7d4aaf8" integrity sha512-fvBeuXOsvqjecUtF/l1dwsrrf5y2BCUk9AOJGzGcm6tE7vegku5u/YvqjyDaAGr422PLoLnrxg3EnRvTqsdC1w== -uid-number@0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE= - -umask@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" - integrity sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0= - unbox-primitive@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" @@ -23783,6 +24213,11 @@ unicode-property-aliases-ecmascript@^2.0.0: resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== +unicorn-magic@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz#1bb9a51c823aaf9d73a8bfcd3d1a23dde94b0ce4" + integrity sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ== + unified@9.2.0: version "9.2.0" resolved "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz#67a62c627c40589edebbf60f53edfd4d822027f8" @@ -23829,6 +24264,13 @@ unique-filename@^1.1.1: dependencies: unique-slug "^2.0.0" +unique-filename@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz#48ba7a5a16849f5080d26c760c86cf5cf05770ea" + integrity sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g== + dependencies: + unique-slug "^4.0.0" + unique-slug@^2.0.0: version "2.0.2" resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" @@ -23836,6 +24278,13 @@ unique-slug@^2.0.0: dependencies: imurmurhash "^0.1.4" +unique-slug@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz#6bae6bb16be91351badd24cdce741f892a6532e3" + integrity sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ== + dependencies: + imurmurhash "^0.1.4" + unist-builder@2.0.3, unist-builder@^2.0.0: version "2.0.3" resolved "https://registry.npmjs.org/unist-builder/-/unist-builder-2.0.3.tgz#77648711b5d86af0942f334397a33c5e91516436" @@ -23947,16 +24396,16 @@ upath2@^3.1.10: path-strip-sep "^1.0.7" tslib "^2.3.1" +upath@2.0.1, upath@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" + integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w== + upath@^1.1.1: version "1.2.0" resolved "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== -upath@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" - integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w== - update-browserslist-db@^1.0.9: version "1.0.10" resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" @@ -24052,13 +24501,6 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -util-promisify@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz#3c2236476c4d32c5ff3c47002add7c13b9a82a53" - integrity sha1-PCI2R2xNMsX/PEcAKt18E7moKlM= - dependencies: - object.getownpropertydescriptors "^2.0.3" - util.promisify@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" @@ -24112,6 +24554,11 @@ uuid@^3.0.1, uuid@^3.3.2, uuid@^3.4.0: resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uuid@^9.0.0: + version "9.0.1" + resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + v8-compile-cache@^2.0.3, v8-compile-cache@^2.1.1: version "2.2.0" resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz#9471efa3ef9128d2f7c6a7ca39c4dd6b5055b132" @@ -24140,7 +24587,7 @@ v8-to-istanbul@^8.1.0: convert-source-map "^1.6.0" source-map "^0.7.3" -validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: +validate-npm-package-license@3.0.4, validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== @@ -24148,6 +24595,13 @@ validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" +validate-npm-package-name@5.0.0, validate-npm-package-name@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz#f16afd48318e6f90a1ec101377fa0384cfc8c713" + integrity sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ== + dependencies: + builtins "^5.0.0" + validate-npm-package-name@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" @@ -24608,7 +25062,7 @@ whatwg-url@^7.0.0: tr46 "^1.0.1" webidl-conversions "^4.0.2" -whatwg-url@^8.0.0, whatwg-url@^8.4.0, whatwg-url@^8.5.0: +whatwg-url@^8.0.0, whatwg-url@^8.5.0: version "8.6.0" resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.6.0.tgz#27c0205a4902084b872aecb97cf0f2a7a3011f4c" integrity sha512-os0KkeeqUOl7ccdDT1qqUcS4KH4tcBTSKK5Nl5WKb2lyxInIZ/CpjkqKa1Ss12mjfdcRX9mHmPPs7/SxG1Hbdw== @@ -24647,14 +25101,14 @@ which@^2.0.1, which@^2.0.2: dependencies: isexe "^2.0.0" -wide-align@^1.1.0: - version "1.1.3" - resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== +which@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/which/-/which-4.0.0.tgz#cd60b5e74503a3fbcfbf6cd6b4138a8bae644c1a" + integrity sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg== dependencies: - string-width "^1.0.2 || 2" + isexe "^3.1.1" -wide-align@^1.1.2: +wide-align@^1.1.2, wide-align@^1.1.5: version "1.1.5" resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== @@ -24704,6 +25158,15 @@ workerpool@6.2.1: resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" @@ -24721,7 +25184,7 @@ wrap-ansi@^5.1.0: string-width "^3.0.0" strip-ansi "^5.0.0" -wrap-ansi@^6.2.0: +wrap-ansi@^6.0.1, wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== @@ -24739,6 +25202,15 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -24753,6 +25225,14 @@ write-file-atomic@2.4.1: imurmurhash "^0.1.4" signal-exit "^3.0.2" +write-file-atomic@5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz#68df4717c55c6fa4281a7860b4c2ba0a6d2b11e7" + integrity sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^4.0.1" + write-file-atomic@^2.3.0, write-file-atomic@^2.4.2: version "2.4.3" resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" @@ -24784,19 +25264,7 @@ write-json-file@^3.2.0: sort-keys "^2.0.0" write-file-atomic "^2.4.2" -write-json-file@^4.3.0: - version "4.3.0" - resolved "https://registry.npmjs.org/write-json-file/-/write-json-file-4.3.0.tgz#908493d6fd23225344af324016e4ca8f702dd12d" - integrity sha512-PxiShnxf0IlnQuMYOPPhPkhExoCQuTUNPOa/2JWCYTmBquU9njyyDuwRKN26IZBlp4yn1nt+Agh2HOOBl+55HQ== - dependencies: - detect-indent "^6.0.0" - graceful-fs "^4.1.15" - is-plain-obj "^2.0.0" - make-dir "^3.0.0" - sort-keys "^4.0.0" - write-file-atomic "^3.0.0" - -write-pkg@^4.0.0: +write-pkg@4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/write-pkg/-/write-pkg-4.0.0.tgz#675cc04ef6c11faacbbc7771b24c0abbf2a20039" integrity sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA== @@ -24869,7 +25337,7 @@ yallist@^2.1.2: resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= -yallist@^3.0.0, yallist@^3.0.2, yallist@^3.1.1: +yallist@^3.0.2: version "3.1.1" resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== @@ -24889,6 +25357,11 @@ yargs-parser@20.2.4: resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== +yargs-parser@21.1.1, yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + yargs-parser@^11.1.1: version "11.1.1" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" @@ -24959,6 +25432,19 @@ yargs@16.2.0, yargs@^16.1.0, yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yargs@17.7.2, yargs@^17.0.0, yargs@^17.6.2: + version "17.7.2" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yargs@^13.3.0, yargs@^13.3.2: version "13.3.2" resolved "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" @@ -25010,6 +25496,11 @@ yocto-queue@^0.1.0: resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== +yocto-queue@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251" + integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g== + zwitch@^1.0.0: version "1.0.5" resolved "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" From a66303d5b199eacdff6223591ce3e5546e71238a Mon Sep 17 00:00:00 2001 From: HelenaIsh <32093844+HelenaIsh@users.noreply.github.com> Date: Tue, 9 Apr 2024 09:03:05 +0500 Subject: [PATCH 002/197] feat(react-ui): update runtime dependencies (#3397) --- packages/react-ui/package.json | 22 +-- yarn.lock | 330 ++++++++++++++++++--------------- 2 files changed, 187 insertions(+), 165 deletions(-) diff --git a/packages/react-ui/package.json b/packages/react-ui/package.json index bbe7b579a0d..e51a7df8726 100644 --- a/packages/react-ui/package.json +++ b/packages/react-ui/package.json @@ -47,24 +47,24 @@ }, "license": "MIT", "dependencies": { - "@babel/runtime": "7.16.5", - "@emotion/css": "^11.7.1", - "@skbkontur/global-object": "^0.4.2", - "eventemitter3": "^4.0.7", - "invariant": "2.2.4", + "@babel/runtime": "^7.24.4", + "@emotion/css": "^11.11.2", + "@skbkontur/global-object": "^0.4.4", + "eventemitter3": "^5.0.1", + "invariant": "^2.2.4", "lodash.debounce": "^4.0.8", "lodash.isequal": "^4.5.0", "lodash.throttle": "^4.1.1", "normalize-wheel": "^1.0.1", - "prop-types": "^15.8.0", - "react-focus-lock": "^2.7.1", - "react-imask": "^7.4.0", + "prop-types": "^15.8.1", + "react-focus-lock": "^2.11.2", + "react-imask": "^7.5.0", "react-input-mask": "2.0.4", - "react-is": "^17.0.2", - "react-transition-group": "^4.4.2", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5", "shallowequal": "^1.1.0", "stylis-plugin-extra-scope": "^0.3.0", - "tabbable": "5.2.1", + "tabbable": "^6.2.0", "warning": "^4.0.3" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index 4e432c31bc6..0202e519f04 100644 --- a/yarn.lock +++ b/yarn.lock @@ -606,6 +606,13 @@ dependencies: "@babel/types" "^7.16.0" +"@babel/helper-module-imports@^7.16.7": + version "7.24.3" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz#6ac476e6d168c7c23ff3ba3cf4f7841d46ac8128" + integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== + dependencies: + "@babel/types" "^7.24.0" + "@babel/helper-module-imports@^7.18.6": version "7.18.6" resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" @@ -892,6 +899,11 @@ resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== +"@babel/helper-string-parser@^7.23.4": + version "7.24.1" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e" + integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== + "@babel/helper-validator-identifier@^7.12.11": version "7.12.11" resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" @@ -912,6 +924,11 @@ resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + "@babel/helper-validator-option@^7.12.17": version "7.12.17" resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" @@ -1726,13 +1743,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-jsx@^7.12.13": - version "7.12.13" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.13.tgz#044fb81ebad6698fe62c478875575bcbb9b70f15" - integrity sha512-d4HM23Q1K7oq/SLNmG6mRt85l2csmQ0cHRaxRXjKW0YFdEXqlZ5kzFQKH5Uc3rDJECgu+yCRgPkG04Mm98R/1g== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-syntax-jsx@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz#000e2e25d8673cce49300517a3eda44c263e4201" @@ -3407,13 +3417,6 @@ core-js-pure "^3.30.2" regenerator-runtime "^0.14.0" -"@babel/runtime@7.16.5": - version "7.16.5" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz#7f3e34bf8bdbbadf03fbb7b1ea0d929569c9487a" - integrity sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA== - dependencies: - regenerator-runtime "^0.13.4" - "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": version "7.13.8" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.8.tgz#cc886a85c072df1de23670dc1aa59fc116c4017c" @@ -3442,6 +3445,13 @@ dependencies: regenerator-runtime "^0.13.11" +"@babel/runtime@^7.18.3", "@babel/runtime@^7.24.4": + version "7.24.4" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz#de795accd698007a66ba44add6cc86542aff1edd" + integrity sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/runtime@^7.9.2": version "7.16.7" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa" @@ -3596,6 +3606,15 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" +"@babel/types@^7.24.0": + version "7.24.0" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz#3b951f435a92e7333eba05b7566fd297960ea1bf" + integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== + dependencies: + "@babel/helper-string-parser" "^7.23.4" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + "@balena/dockerignore@^1.0.2": version "1.0.2" resolved "https://registry.npmjs.org/@balena/dockerignore/-/dockerignore-1.0.2.tgz#9ffe4726915251e8eb69f44ef3547e0da2c03e0d" @@ -3820,23 +3839,22 @@ resolved "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@emotion/babel-plugin@^11.7.1": - version "11.7.2" - resolved "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz#fec75f38a6ab5b304b0601c74e2a5e77c95e5fa0" - integrity sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ== - dependencies: - "@babel/helper-module-imports" "^7.12.13" - "@babel/plugin-syntax-jsx" "^7.12.13" - "@babel/runtime" "^7.13.10" - "@emotion/hash" "^0.8.0" - "@emotion/memoize" "^0.7.5" - "@emotion/serialize" "^1.0.2" - babel-plugin-macros "^2.6.1" +"@emotion/babel-plugin@^11.11.0": + version "11.11.0" + resolved "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz#c2d872b6a7767a9d176d007f5b31f7d504bb5d6c" + integrity sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/runtime" "^7.18.3" + "@emotion/hash" "^0.9.1" + "@emotion/memoize" "^0.8.1" + "@emotion/serialize" "^1.1.2" + babel-plugin-macros "^3.1.0" convert-source-map "^1.5.0" escape-string-regexp "^4.0.0" find-root "^1.1.0" source-map "^0.5.7" - stylis "4.0.13" + stylis "4.2.0" "@emotion/cache@^10.0.27": version "10.0.29" @@ -3848,16 +3866,16 @@ "@emotion/utils" "0.11.3" "@emotion/weak-memoize" "0.2.5" -"@emotion/cache@^11.7.1": - version "11.7.1" - resolved "https://registry.npmjs.org/@emotion/cache/-/cache-11.7.1.tgz#08d080e396a42e0037848214e8aa7bf879065539" - integrity sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A== +"@emotion/cache@^11.11.0": + version "11.11.0" + resolved "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz#809b33ee6b1cb1a625fef7a45bc568ccd9b8f3ff" + integrity sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ== dependencies: - "@emotion/memoize" "^0.7.4" - "@emotion/sheet" "^1.1.0" - "@emotion/utils" "^1.0.0" - "@emotion/weak-memoize" "^0.2.5" - stylis "4.0.13" + "@emotion/memoize" "^0.8.1" + "@emotion/sheet" "^1.2.2" + "@emotion/utils" "^1.2.1" + "@emotion/weak-memoize" "^0.3.1" + stylis "4.2.0" "@emotion/core@^10.1.1": version "10.1.1" @@ -3880,22 +3898,27 @@ "@emotion/utils" "0.11.3" babel-plugin-emotion "^10.0.27" -"@emotion/css@^11.7.1": - version "11.7.1" - resolved "https://registry.npmjs.org/@emotion/css/-/css-11.7.1.tgz#516b717340d36b0bbd2304ba7e1a090e866f8acc" - integrity sha512-RUUgPlMZunlc7SE5A6Hg+VWRzb2cU6O9xlV78KCFgcnl25s7Qz/20oQg71iKudpLqk7xj0vhbJlwcJJMT0BOZg== +"@emotion/css@^11.11.2": + version "11.11.2" + resolved "https://registry.npmjs.org/@emotion/css/-/css-11.11.2.tgz#e5fa081d0c6e335352e1bc2b05953b61832dca5a" + integrity sha512-VJxe1ucoMYMS7DkiMdC2T7PWNbrEI0a39YRiyDvK2qq4lXwjRbVP/z4lpG+odCsRzadlR+1ywwrTzhdm5HNdew== dependencies: - "@emotion/babel-plugin" "^11.7.1" - "@emotion/cache" "^11.7.1" - "@emotion/serialize" "^1.0.0" - "@emotion/sheet" "^1.0.3" - "@emotion/utils" "^1.0.0" + "@emotion/babel-plugin" "^11.11.0" + "@emotion/cache" "^11.11.0" + "@emotion/serialize" "^1.1.2" + "@emotion/sheet" "^1.2.2" + "@emotion/utils" "^1.2.1" -"@emotion/hash@0.8.0", "@emotion/hash@^0.8.0": +"@emotion/hash@0.8.0": version "0.8.0" resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== +"@emotion/hash@^0.9.1": + version "0.9.1" + resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz#4ffb0055f7ef676ebc3a5a91fb621393294e2f43" + integrity sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ== + "@emotion/is-prop-valid@0.8.8", "@emotion/is-prop-valid@^0.8.6", "@emotion/is-prop-valid@^0.8.8": version "0.8.8" resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" @@ -3908,10 +3931,10 @@ resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== -"@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5": - version "0.7.5" - resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50" - integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ== +"@emotion/memoize@^0.8.1": + version "0.8.1" + resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17" + integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA== "@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16": version "0.11.16" @@ -3924,26 +3947,15 @@ "@emotion/utils" "0.11.3" csstype "^2.5.7" -"@emotion/serialize@^1.0.0": - version "1.0.1" - resolved "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.1.tgz#322cdebfdbb5a88946f17006548191859b9b0855" - integrity sha512-TXlKs5sgUKhFlszp/rg4lIAZd7UUSmJpwaf9/lAEFcUh2vPi32i7x4wk7O8TN8L8v2Ol8k0CxnhRBY0zQalTxA== - dependencies: - "@emotion/hash" "^0.8.0" - "@emotion/memoize" "^0.7.4" - "@emotion/unitless" "^0.7.5" - "@emotion/utils" "^1.0.0" - csstype "^3.0.2" - -"@emotion/serialize@^1.0.2": - version "1.0.2" - resolved "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.2.tgz#77cb21a0571c9f68eb66087754a65fa97bfcd965" - integrity sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A== +"@emotion/serialize@^1.1.2": + version "1.1.4" + resolved "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.4.tgz#fc8f6d80c492cfa08801d544a05331d1cc7cd451" + integrity sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ== dependencies: - "@emotion/hash" "^0.8.0" - "@emotion/memoize" "^0.7.4" - "@emotion/unitless" "^0.7.5" - "@emotion/utils" "^1.0.0" + "@emotion/hash" "^0.9.1" + "@emotion/memoize" "^0.8.1" + "@emotion/unitless" "^0.8.1" + "@emotion/utils" "^1.2.1" csstype "^3.0.2" "@emotion/sheet@0.9.4": @@ -3951,10 +3963,10 @@ resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5" integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA== -"@emotion/sheet@^1.0.3", "@emotion/sheet@^1.1.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.1.0.tgz#56d99c41f0a1cda2726a05aa6a20afd4c63e58d2" - integrity sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g== +"@emotion/sheet@^1.2.2": + version "1.2.2" + resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz#d58e788ee27267a14342303e1abb3d508b6d0fec" + integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA== "@emotion/styled-base@^10.0.27": version "10.0.31" @@ -3979,26 +3991,36 @@ resolved "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== -"@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.4", "@emotion/unitless@^0.7.5": +"@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.4": version "0.7.5" resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== +"@emotion/unitless@^0.8.1": + version "0.8.1" + resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz#182b5a4704ef8ad91bde93f7a860a88fd92c79a3" + integrity sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ== + "@emotion/utils@0.11.3": version "0.11.3" resolved "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz#a759863867befa7e583400d322652a3f44820924" integrity sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw== -"@emotion/utils@^1.0.0": - version "1.0.0" - resolved "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz#abe06a83160b10570816c913990245813a2fd6af" - integrity sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA== +"@emotion/utils@^1.2.1": + version "1.2.1" + resolved "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz#bbab58465738d31ae4cb3dbb6fc00a5991f755e4" + integrity sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg== -"@emotion/weak-memoize@0.2.5", "@emotion/weak-memoize@^0.2.5": +"@emotion/weak-memoize@0.2.5": version "0.2.5" resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== +"@emotion/weak-memoize@^0.3.1": + version "0.3.1" + resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6" + integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww== + "@eslint/eslintrc@^0.4.0": version "0.4.0" resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz#99cc0a0584d72f1df38b900fb062ba995f395547" @@ -5323,10 +5345,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@skbkontur/global-object@^0.4.2": - version "0.4.2" - resolved "https://registry.npmjs.org/@skbkontur/global-object/-/global-object-0.4.2.tgz#c5e42388ec6424b27093e5cd1ebc2225b1fdf316" - integrity sha512-Sn1F4+rJkgagzxlgmcyQQHiD0s66kVWXBh3Efy8writSMxc/7dsNxPW4zFJGynaJhgzn3ZHOfY9d08G9M/Yjyw== +"@skbkontur/global-object@^0.4.4": + version "0.4.4" + resolved "https://registry.npmjs.org/@skbkontur/global-object/-/global-object-0.4.4.tgz#216f2b8370547ccc2bf1af63f68b80207714a777" + integrity sha512-GC6UKPxTNDG7jGC7OIIoiI97lMSpq7zIU8F46HpdKuPfJsdToxHYrrez51cgJnL8EDjUfydqf1Hmqpw+tjd9Zw== "@skbkontur/icons@1.5.1": version "1.5.1" @@ -8548,7 +8570,7 @@ babel-plugin-jest-hoist@^27.4.0: "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" -babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.6.1, babel-plugin-macros@^2.8.0: +babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.8.0: version "2.8.0" resolved "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== @@ -8557,7 +8579,7 @@ babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.6.1, babel-plugin-macros@^2.8 cosmiconfig "^6.0.0" resolve "^1.12.0" -babel-plugin-macros@^3.0.1: +babel-plugin-macros@^3.0.1, babel-plugin-macros@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg== @@ -12192,11 +12214,16 @@ event-source-polyfill@1.0.25: resolved "https://registry.npmjs.org/event-source-polyfill/-/event-source-polyfill-1.0.25.tgz#d8bb7f99cb6f8119c2baf086d9f6ee0514b6d9c8" integrity sha512-hQxu6sN1Eq4JjoI7ITdQeGGUN193A2ra83qC0Ltm9I2UJVAten3OFVN6k5RX4YWeCS0BoC8xg/5czOCIHVosQg== -eventemitter3@^4.0.0, eventemitter3@^4.0.4, eventemitter3@^4.0.7: +eventemitter3@^4.0.0, eventemitter3@^4.0.4: version "4.0.7" resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== +eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + events@^3.0.0: version "3.3.0" resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" @@ -12868,10 +12895,10 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" -focus-lock@^0.10.1: - version "0.10.1" - resolved "https://registry.npmjs.org/focus-lock/-/focus-lock-0.10.1.tgz#5f46fa74fefb87144479c2f8e276f0eedd8081b2" - integrity sha512-b9yUklCi4fTu2GXn7dnaVf4hiLVVBp7xTiZarAHMODV2To6Bitf6F/UI67RmKbdgJQeVwI1UO0d9HYNbXt3GkA== +focus-lock@^1.3.2: + version "1.3.4" + resolved "https://registry.npmjs.org/focus-lock/-/focus-lock-1.3.4.tgz#a143aa327224df2e83414f87e8a3328cb5a62156" + integrity sha512-Gv0N3mvej3pD+HWkNryrF8sExzEHqhQ6OSFxD4DPxm9n5HGCaHme98ZMBZroNEAJcsdtHxk+skvThGKyUeoEGA== dependencies: tslib "^2.0.3" @@ -14437,10 +14464,10 @@ image-size@~0.5.0: resolved "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w= -imask@^7.4.0: - version "7.4.0" - resolved "https://registry.npmjs.org/imask/-/imask-7.4.0.tgz#02f69ad6d68625557a76398c9fcedfe755d06841" - integrity sha512-fU6mCo5YiTeDI8aVreuOKLOWxXIrRVnuQhZQXbjhwHxQb3GOQyCtlDGMyHxu2gq//LnKDxTwDBq1teRHmkzA3Q== +imask@^7.5.0: + version "7.5.0" + resolved "https://registry.npmjs.org/imask/-/imask-7.5.0.tgz#dc191f3297794ecc9afc62041816a2909a8d36bd" + integrity sha512-eoTEnw67KAamB1zsiYtU35s0Fj1XYZ8mN2q3ZDGO4ot4FtPmBpw9S6kOTj0kaOILdsEA6ZhNtH2TAMXe/NChmQ== dependencies: "@babel/runtime-corejs3" "^7.23.9" @@ -14667,7 +14694,7 @@ interpret@^2.2.0: resolved "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== -invariant@2.2.4, invariant@^2.2.4: +invariant@^2.2.4: version "2.2.4" resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -17053,7 +17080,7 @@ jss@10.5.1, jss@^10.0.0: jszip@^3.6.0: version "3.10.1" - resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" + resolved "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== dependencies: lie "~3.3.0" @@ -20723,10 +20750,10 @@ rc@^1.0.1, rc@^1.1.6: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-clientside-effect@^1.2.5: - version "1.2.5" - resolved "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.2.5.tgz#e2c4dc3c9ee109f642fac4f5b6e9bf5bcd2219a3" - integrity sha512-2bL8qFW1TGBHozGGbVeyvnggRpMjibeZM2536AKNENLECutp2yfs44IL8Hmpn8qjFQ2K7A9PnYf3vc7aQq/cPA== +react-clientside-effect@^1.2.6: + version "1.2.6" + resolved "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.2.6.tgz#29f9b14e944a376b03fb650eed2a754dd128ea3a" + integrity sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg== dependencies: "@babel/runtime" "^7.12.13" @@ -20844,17 +20871,17 @@ react-fast-compare@^3.0.1, react-fast-compare@^3.1.1, react-fast-compare@^3.2.0: resolved "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== -react-focus-lock@^2.7.1: - version "2.7.1" - resolved "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.7.1.tgz#a9fbb3fa4efaee32162406e5eb96ae658964193b" - integrity sha512-ImSeVmcrLKNMqzUsIdqOkXwTVltj79OPu43oT8tVun7eIckA4VdM7UmYUFo3H/UC2nRVgagMZGFnAOQEDiDYcA== +react-focus-lock@^2.11.2: + version "2.11.2" + resolved "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.11.2.tgz#dcc9a0dde630f0b9c694b823066f1b954c024422" + integrity sha512-DDTbEiov0+RthESPVSTIdAWPPKic+op3sCcP+icbMRobvQNt7LuAlJ3KoarqQv5sCgKArru3kXmlmFTa27/CdQ== dependencies: "@babel/runtime" "^7.0.0" - focus-lock "^0.10.1" + focus-lock "^1.3.2" prop-types "^15.6.2" - react-clientside-effect "^1.2.5" - use-callback-ref "^1.2.5" - use-sidecar "^1.0.5" + react-clientside-effect "^1.2.6" + use-callback-ref "^1.3.0" + use-sidecar "^1.1.2" react-group@^3.0.2: version "3.0.2" @@ -20905,12 +20932,12 @@ react-icons@^3.8.0: dependencies: camelcase "^5.0.0" -react-imask@^7.4.0: - version "7.4.0" - resolved "https://registry.npmjs.org/react-imask/-/react-imask-7.4.0.tgz#59d776046acedc7c3e608a6f93cfe09d825db119" - integrity sha512-U7O2IhIKIGF0ch16xBinwbWGfsgeDyM3KcftD8/bWLuES+KQOjv8wCjX2QZNiAqsZ3FgSembaJmqAN8XlB5LbA== +react-imask@^7.5.0: + version "7.5.0" + resolved "https://registry.npmjs.org/react-imask/-/react-imask-7.5.0.tgz#ba751c3b29c263fc47293e49755a5f0a369a12f8" + integrity sha512-yWExhHphDmNaHvmOsYR+5QcludeBdYk6bXyo8kouIJFAub5sF+O0kLPVupg2yhd7EfTqjLswFZ/tqY1AhKnd9Q== dependencies: - imask "^7.4.0" + imask "^7.5.0" prop-types "^15.8.1" react-input-mask@2.0.4: @@ -20945,7 +20972,7 @@ react-is@^17.0.1: resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== -react-is@^18.0.0: +react-is@^18.0.0, react-is@^18.2.0: version "18.2.0" resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== @@ -21228,10 +21255,10 @@ react-textarea-autosize@^8.3.0: use-composed-ref "^1.0.0" use-latest "^1.0.0" -react-transition-group@^4.4.2: - version "4.4.2" - resolved "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470" - integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg== +react-transition-group@^4.4.5: + version "4.4.5" + resolved "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" + integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== dependencies: "@babel/runtime" "^7.5.5" dom-helpers "^5.0.1" @@ -22188,7 +22215,7 @@ select@^1.1.2: selenium-webdriver@4.0.0-beta.4, selenium-webdriver@^4.3.1: version "4.0.0-beta.4" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.0.0-beta.4.tgz#db4fc7505a515ea3b4a95ded031b738a1544eddd" + resolved "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.0.0-beta.4.tgz#db4fc7505a515ea3b4a95ded031b738a1544eddd" integrity sha512-+s/CIYkWzmnC9WASBxxVj7Lm0dcyl6OaFxwIJaFCT5WCuACiimEEr4lUnOOFP/QlKfkDQ56m+aRczaq2EvJEJg== dependencies: jszip "^3.6.0" @@ -23368,10 +23395,10 @@ stylis-plugin-extra-scope@^0.3.0: resolved "https://registry.npmjs.org/stylis-plugin-extra-scope/-/stylis-plugin-extra-scope-0.3.0.tgz#8a19135273856694f7559a78d4d7a48928cd03e4" integrity sha512-SaZ+SQk9saypYdJPmVv0cboRGyknxtvWdw1eCphd24wYKdgLdoLMZrZi4w3F24mLFCd+De8hCTPcfJXmL+C1Xg== -stylis@4.0.13: - version "4.0.13" - resolved "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91" - integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag== +stylis@4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" + integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw== supports-color@8.1.1, supports-color@^8.0.0: version "8.1.1" @@ -23439,10 +23466,10 @@ synchronous-promise@^2.0.15: resolved "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.16.tgz#669b75e86b4295fdcc1bb0498de9ac1af6fd51a9" integrity sha512-qImOD23aDfnIDNqlG1NOehdB9IYsn1V9oByPjKY1nakv2MQYCEMyX033/q+aEtYCpmYK1cv2+NTmlH+ra6GA5A== -tabbable@5.2.1: - version "5.2.1" - resolved "https://registry.npmjs.org/tabbable/-/tabbable-5.2.1.tgz#e3fda7367ddbb172dcda9f871c0fdb36d1c4cd9c" - integrity sha512-40pEZ2mhjaZzK0BnI+QGNjJO8UYx9pP5v7BGe17SORTO0OEuuaAwQTkAp8whcZvqon44wKFOikD+Al11K3JICQ== +tabbable@^6.2.0: + version "6.2.0" + resolved "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz#732fb62bc0175cfcec257330be187dcfba1f3b97" + integrity sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew== table@^6.0.4: version "6.0.7" @@ -23738,14 +23765,7 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" -tmp@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" - integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== - dependencies: - rimraf "^3.0.0" - -tmp@~0.2.1: +tmp@^0.2.1, tmp@~0.2.1: version "0.2.3" resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== @@ -23981,7 +24001,7 @@ tslib@2.3.1, tslib@^2.3.1: resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== -tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.2, tslib@^1.9.3: +tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.2: version "1.14.1" resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -23991,16 +24011,16 @@ tslib@^2.0.0: resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== -tslib@^2.0.1, tslib@^2.0.3, tslib@~2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" - integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== - -tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0: +tslib@^2.0.1, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0: version "2.6.2" resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== +tslib@^2.0.3, tslib@~2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" + integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== + tsscmp@1.0.6: version "1.0.6" resolved "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" @@ -24459,10 +24479,12 @@ url@^0.11.0: punycode "1.3.2" querystring "0.2.0" -use-callback-ref@^1.2.5: - version "1.2.5" - resolved "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.5.tgz#6115ed242cfbaed5915499c0a9842ca2912f38a5" - integrity sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg== +use-callback-ref@^1.3.0: + version "1.3.2" + resolved "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz#6134c7f6ff76e2be0b56c809b17a650c942b1693" + integrity sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA== + dependencies: + tslib "^2.0.0" use-composed-ref@^1.0.0: version "1.1.0" @@ -24483,13 +24505,13 @@ use-latest@^1.0.0: dependencies: use-isomorphic-layout-effect "^1.0.0" -use-sidecar@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.0.5.tgz#ffff2a17c1df42e348624b699ba6e5c220527f2b" - integrity sha512-k9jnrjYNwN6xYLj1iaGhonDghfvmeTmYjAiGvOr7clwKfPjMXJf4/HOr7oT5tJwYafgp2tG2l3eZEOfoELiMcA== +use-sidecar@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2" + integrity sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw== dependencies: detect-node-es "^1.1.0" - tslib "^1.9.3" + tslib "^2.0.0" use@^3.1.0: version "3.1.1" @@ -25274,9 +25296,9 @@ write-pkg@4.0.0: write-json-file "^3.2.0" ws@>=7.4.6: - version "8.13.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" - integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== + version "8.16.0" + resolved "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" + integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== ws@^5.2.0: version "5.2.3" From be200240a8cf1a492e0a7df6a443c7f2b9e3800a Mon Sep 17 00:00:00 2001 From: HelenaIsh <32093844+HelenaIsh@users.noreply.github.com> Date: Mon, 22 Apr 2024 12:45:31 +0500 Subject: [PATCH 003/197] feat(react-ui): update react and testing packages (#3402) --- package.json | 4 +- .../react-ui-validations/docs/Common/Form.tsx | 2 +- packages/react-ui-validations/docs/Layout.tsx | 20 +- packages/react-ui-validations/docs/index.tsx | 14 +- packages/react-ui-validations/package.json | 18 +- .../components/Preview/Preview.tsx | 8 +- .../components/Autocomplete/Autocomplete.tsx | 2 +- .../__tests__/Autocomplete-test.tsx | 39 +- .../Button/__tests__/Button-test.tsx | 50 +- .../Calendar/__tests__/Calendar.test.tsx | 60 +- .../react-ui/components/Checkbox/Checkbox.tsx | 2 +- .../Checkbox/__stories__/Checkbox.stories.tsx | 4 +- .../Checkbox/__tests__/Checkbox-test.tsx | 30 +- .../react-ui/components/ComboBox/ComboBox.tsx | 2 +- .../ComboBox/__stories__/Combobox.stories.tsx | 2 +- .../ComboBox/__tests__/ComboBox-test.tsx | 206 +- .../CurrencyInput/CurrencyInput.tsx | 2 +- .../__tests__/CurrencyInput-test.tsx | 132 +- .../DateInput/__tests__/DateInput-test.tsx | 44 +- .../components/DatePicker/DatePicker.tsx | 2 +- .../DatePicker/__tests__/DatePicker-test.tsx | 98 +- .../Dropdown/__stories__/Dropdown.stories.tsx | 2 +- .../Dropdown/__tests__/Dropdown-test.tsx | 26 +- .../DropdownMenu.creevey.stories.tsx | 2 +- .../__stories__/DropdownMenu.stories.tsx | 2 +- .../__tests__/DropdownMenu-test.tsx | 57 +- .../components/FileUploader/FileUploader.tsx | 10 +- .../__tests__/FileUploader-test.tsx | 17 +- .../FxInput/__stories__/FxInput.stories.tsx | 2 +- .../FxInput/__tests__/FxInput-test.tsx | 6 +- .../Gapped/__stories__/Gapped.stories.tsx | 2 +- .../__tests__/GlobalLoader-test.tsx | 30 +- .../Hint/__stories__/Hint.stories.tsx | 2 +- .../components/Hint/__tests__/Hint-test.tsx | 17 +- packages/react-ui/components/Input/Input.tsx | 2 +- .../InputLayout/InputLayoutAsideIcon.tsx | 34 +- .../InputLayout/InputLayoutAsideText.tsx | 12 +- .../components/Input/__tests__/Input-test.tsx | 113 +- packages/react-ui/components/Kebab/Kebab.tsx | 6 +- .../__stories__/Kebab.creevey.stories.tsx | 2 +- .../Kebab/__stories__/Kebab.stories.tsx | 2 +- .../components/Kebab/__tests__/Kebab-test.tsx | 18 +- .../components/Link/__tests__/Link-test.tsx | 16 +- .../Loader/__stories__/Loader.stories.tsx | 2 +- .../__tests__/MaskedInput-test.tsx | 16 +- .../react-ui/components/MenuItem/MenuItem.tsx | 4 +- .../MenuItem/__tests__/MenuItem-test.tsx | 18 +- .../components/MiniModal/MiniModalHeader.tsx | 7 +- .../components/MiniModal/MiniModalIndent.tsx | 2 +- .../Modal/__stories__/Modal.stories.tsx | 2 +- .../components/Modal/__tests__/Modal-test.tsx | 12 +- .../Paging/__stories__/Paging.stories.tsx | 2 +- .../Paging/__tests__/Paging-test.tsx | 4 +- .../PasswordInput/PasswordInput.tsx | 2 +- .../__tests__/PasswordInput-test.tsx | 44 +- packages/react-ui/components/Radio/Radio.tsx | 2 +- .../components/Radio/__tests__/Radio-test.tsx | 12 +- .../components/RadioGroup/RadioGroup.tsx | 2 +- .../RadioGroup/__tests__/RadioGroup-test.tsx | 24 +- .../__stories__/ScrollContainer.stories.tsx | 18 +- .../react-ui/components/Select/Select.tsx | 2 +- .../Select/__stories__/Select.stories.tsx | 15 +- .../Select/__tests__/Select-test.tsx | 351 +- .../components/SidePage/SidePageFooter.tsx | 2 +- .../SidePage/__tests__/SidePage.test.tsx | 4 +- .../__tests__/SingleToast.test.tsx | 6 +- .../Spinner/__stories__/Spinner.stories.tsx | 2 +- .../Sticky/__stories__/Sticky.stories.tsx | 6 +- .../Switcher/__tests__/Switcher-test.tsx | 12 +- .../Tabs/__stories__/Tabs.stories.tsx | 2 +- .../components/Tabs/__tests__/Tab.test.tsx | 38 +- .../components/Tabs/__tests__/Tabs-test.tsx | 6 +- .../react-ui/components/Textarea/Textarea.tsx | 2 +- .../components/Textarea/TextareaCounter.tsx | 9 +- .../Textarea/__tests__/Textarea-test.tsx | 79 +- .../react-ui/components/Toast/ToastView.tsx | 2 +- .../Toast/__stories__/Toast.stories.tsx | 2 +- .../components/Toast/__tests__/Toast-test.tsx | 69 +- .../Toast/__tests__/ToastView.test.tsx | 6 +- .../Toggle/__tests__/Toggle-test.tsx | 16 +- .../Token/__stories__/Token.stories.tsx | 2 +- .../components/TokenInput/TokenInput.tsx | 2 +- .../__stories__/TokenInput.stories.tsx | 2 +- .../TokenInput/__tests__/TokenInput-test.tsx | 71 +- .../Tooltip/__stories__/Tooltip.stories.tsx | 2 +- .../Tooltip/__tests__/Tooltip-test.tsx | 150 +- .../TooltipMenu.creevey.stories.tsx | 2 +- .../__stories__/TooltipMenu.stories.tsx | 2 +- .../__tests__/TooltipMenu-test.tsx | 14 +- .../__tests__/PropsForwarding-test.tsx | 11 +- packages/react-ui/hooks/useDrop.ts | 10 +- .../internal/CommonWrapper/CommonWrapper.tsx | 4 +- .../internal/CustomComboBox/ComboBoxMenu.tsx | 2 +- .../internal/CustomComboBox/ComboBoxView.tsx | 10 +- .../CustomComboBox/CustomComboBox.tsx | 2 +- .../__stories__/ComboBoxView.stories.tsx | 5 +- .../DateSelect/__tests__/DateSelect-test.tsx | 8 +- .../__stories__/DropdownContainer.stories.tsx | 10 +- .../FileUploaderControl/hooks/useUpload.ts | 6 +- .../HideBodyVerticalScroll.stories.tsx | 2 +- .../internal/InputLikeText/InputLikeText.tsx | 2 +- .../InternalMaskedInput.tsx | 6 +- .../__tests__/InternalMenu-test.tsx | 47 +- .../Menu/__stories__/Menu.stories.tsx | 4 +- .../internal/Menu/__tests__/Menu-test.tsx | 30 +- .../internal/MobilePopup/MobilePopup.tsx | 1 + .../MobilePopupHeader/MobilePopupHeader.tsx | 2 +- .../PerformanceMetrics/PerformanceMetrics.tsx | 11 +- packages/react-ui/internal/Popup/Popup.tsx | 4 +- .../internal/Popup/__tests__/Popup-test.tsx | 3 + .../__stories__/PopupMenu.creevey.stories.tsx | 2 +- .../PopupMenu/__tests__/PopupMenu-test.tsx | 32 +- .../ResizeDetector/ResizeDetector.tsx | 2 +- .../internal/ZIndex/__tests__/ZIndex-test.tsx | 12 +- packages/react-ui/jest.config.js | 2 +- .../__tests__/reactGetTextContent-test.tsx | 2 +- .../rootNode/__tests__/getRootNode-test.tsx | 8 +- .../lib/rootNode/rootNodeDecorator.tsx | 2 +- packages/react-ui/package.json | 35 +- packages/react-ui/test-setup.js | 2 +- yarn.lock | 7644 +++++------------ 121 files changed, 3607 insertions(+), 6488 deletions(-) diff --git a/package.json b/package.json index 201dac84b48..fd1807a3ba7 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,8 @@ }, "private": true, "devDependencies": { - "@commitlint/cli": "^19.2.1", - "@commitlint/config-conventional": "^19.1.0", + "@commitlint/cli": "^19.2.2", + "@commitlint/config-conventional": "^19.2.2", "@skbkontur/eslint-config": "*", "commitizen": "^4.3.0", "cz-conventional-changelog": "^3.3.0", diff --git a/packages/react-ui-validations/docs/Common/Form.tsx b/packages/react-ui-validations/docs/Common/Form.tsx index 7213cf899f6..d1a13ed1b4c 100644 --- a/packages/react-ui-validations/docs/Common/Form.tsx +++ b/packages/react-ui-validations/docs/Common/Form.tsx @@ -23,7 +23,7 @@ interface FormLineProps { title: React.ReactNode; } -const FormLine: React.SFC = (props) => { +const FormLine: React.FC = (props) => { return ( {props.title} diff --git a/packages/react-ui-validations/docs/Layout.tsx b/packages/react-ui-validations/docs/Layout.tsx index 056a08e5371..8714e4523fe 100644 --- a/packages/react-ui-validations/docs/Layout.tsx +++ b/packages/react-ui-validations/docs/Layout.tsx @@ -1,6 +1,6 @@ import React from 'react'; import Helmet from 'react-helmet'; -import { NavLink, withRouter } from 'react-router-dom'; +import { NavLink, useNavigate } from 'react-router-dom'; import styled from 'styled-components'; import { Displaying } from './Pages/Displaying'; @@ -8,8 +8,12 @@ import { Validator } from './Pages/Validator'; import { Examples } from './Pages/Examples'; import { Concepts } from './Pages/Concepts'; -export const Layout = withRouter((props) => { - window.scrollTo(0, 0); +export const Layout: React.FC = (props) => { + const navigate = useNavigate(); + React.useEffect(() => { + window.scrollTo(0, 0); + }, [navigate]); + return ( @@ -18,7 +22,7 @@ export const Layout = withRouter((props) => {

react-ui-validations

- + (isActive ? 'active' : '')} to="/api"> API reference @@ -26,7 +30,11 @@ export const Layout = withRouter((props) => {
{x.caption}
{x.items.map((page) => ( - + (isActive ? 'active' : '')} + to={'/' + page.url} + > {page.caption} ))} @@ -39,7 +47,7 @@ export const Layout = withRouter((props) => { ); -}); +}; const navigationBarSize = '290px'; const sidebarColor = '#41464e'; diff --git a/packages/react-ui-validations/docs/index.tsx b/packages/react-ui-validations/docs/index.tsx index fec601919ff..a51d5a6a83f 100644 --- a/packages/react-ui-validations/docs/index.tsx +++ b/packages/react-ui-validations/docs/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { render } from 'react-dom'; import { hot } from 'react-hot-loader/root'; -import { HashRouter as Router, Route, Switch } from 'react-router-dom'; +import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import { Layout } from './Layout'; import Api from './Pages/Api.md'; @@ -17,14 +17,14 @@ import 'docs/styles/typography.less'; const App = hot(() => ( - - + + } /> {[...Examples.items, ...Displaying.items, ...Validator.items, ...Concepts.items].map((page) => ( - + ))} - - - + } /> + } /> + )); diff --git a/packages/react-ui-validations/package.json b/packages/react-ui-validations/package.json index a69e0680a3f..96eb5b6ee31 100644 --- a/packages/react-ui-validations/package.json +++ b/packages/react-ui-validations/package.json @@ -19,7 +19,7 @@ "storybook": "node ../../scripts/patch-node-options.js \"cross-env STORYBOOK_REACT_UI_TEST=true start-storybook -p 8081\"", "storybook:build": "node ../../scripts/patch-node-options.js \"cross-env STORYBOOK_REACT_UI_TEST=true build-storybook -o .storybook/build --quiet\"", "storybook:serve": "serve -l 8081 .storybook/build", - "start:docs": "webpack-dev-server -d --config webpack.docs.config.js --hot", + "start:docs": "node ../../scripts/patch-node-options.js \"webpack-dev-server -d --config webpack.docs.config.js --hot\"", "lint": "npm-run-all --continue-on-error --parallel lint:*", "lint:tsc": "tsc --noEmit --diagnostics", "lint:eslint": "cross-env TIMING=1 eslint --ext .js,.jsx,.ts,.tsx ./", @@ -48,8 +48,8 @@ "index.js.map" ], "peerDependencies": { - "react": ">=16.9", - "react-dom": ">=16.9", + "react": ">=17.0.2", + "react-dom": ">=17.0.2", "retail-ui": ">=0.53.7" }, "dependencies": { @@ -76,10 +76,10 @@ "@testing-library/react-hooks": "7.0.2", "@testing-library/user-event": "13.5.0", "@types/jest": "^26.0.20", - "@types/react": "17.0.38", - "@types/react-dom": "17.0.11", + "@types/react": "18.2.79", + "@types/react-dom": "18.2.25", "@types/react-helmet": "^6.1.4", - "@types/react-router-dom": "^5.1.3", + "@types/react-router-dom": "^5.3.3", "@types/react-syntax-highlighter": "^13.5.0", "@types/styled-components": "^5.1.7", "@types/warning": "^3.0.0", @@ -101,11 +101,11 @@ "markdown": "^0.5.0", "npm-run-all": "^4.1.5", "raw-loader": "^4.0.0", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", "react-helmet": "^6.1.0", "react-hot-loader": "^4.13.0", - "react-router-dom": "^5.1.2", + "react-router-dom": "^6.22.3", "react-syntax-highlighter": "15.4.5", "rimraf": "^3.0.0", "rollup": "^2.62.0", diff --git a/packages/react-ui/.styleguide/components/Preview/Preview.tsx b/packages/react-ui/.styleguide/components/Preview/Preview.tsx index b24f7c84b2d..82ae8d4a01b 100644 --- a/packages/react-ui/.styleguide/components/Preview/Preview.tsx +++ b/packages/react-ui/.styleguide/components/Preview/Preview.tsx @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import ReactDOM from 'react-dom'; +import { createRoot } from 'react-dom/client'; import PlaygroundError from 'react-styleguidist/lib/client/rsg-components/PlaygroundError'; import ReactExample from 'react-styleguidist/lib/client/rsg-components/ReactExample'; import Context from 'react-styleguidist/lib/client/rsg-components/Context'; @@ -72,7 +72,8 @@ const Preview = withContext( public unmountPreview() { if (this.mountNode) { - ReactDOM.unmountComponentAtNode(this.mountNode); + const root = createRoot(this.mountNode); + root.unmount(); } } @@ -100,7 +101,8 @@ const Preview = withContext( window.requestAnimationFrame(() => { // this.unmountPreview(); try { - ReactDOM.render(wrappedComponent, this.mountNode); + const root = createRoot(this.mountNode); + root.render(wrappedComponent); } catch (err) { this.handleError(err as Error); } diff --git a/packages/react-ui/components/Autocomplete/Autocomplete.tsx b/packages/react-ui/components/Autocomplete/Autocomplete.tsx index f829ea16c73..e97919b3a63 100644 --- a/packages/react-ui/components/Autocomplete/Autocomplete.tsx +++ b/packages/react-ui/components/Autocomplete/Autocomplete.tsx @@ -201,7 +201,7 @@ export class Autocomplete extends React.Component - + {this.renderMain} diff --git a/packages/react-ui/components/Autocomplete/__tests__/Autocomplete-test.tsx b/packages/react-ui/components/Autocomplete/__tests__/Autocomplete-test.tsx index f2218ee2b93..eb9201e1f61 100644 --- a/packages/react-ui/components/Autocomplete/__tests__/Autocomplete-test.tsx +++ b/packages/react-ui/components/Autocomplete/__tests__/Autocomplete-test.tsx @@ -126,7 +126,7 @@ describe('', () => { expect(screen.getByPlaceholderText('SomePlaceholder')).toBeInTheDocument(); }); - it('passes maxLength prop to input and it works', () => { + it('passes maxLength prop to input and it works', async () => { const Comp = () => { const [value, setValue] = useState(''); @@ -142,26 +142,26 @@ describe('', () => { const input = screen.getByRole('textbox'); expect(input).toHaveValue(''); - userEvent.type(input, '123456'); + await userEvent.type(input, '123456'); expect(input).toHaveValue('12345'); }); it('passes leftIcon prop to input', () => { const onValueChange = jest.fn(); const source: any[] = []; - const leftIcon = ; + const leftIcon = ; const props = { value: 'hello', onValueChange, source, leftIcon }; render(); - expect(document.querySelector('.my-testy-icon')).toBeInTheDocument(); + expect(screen.getByTestId('my-testy-icon')).toBeInTheDocument(); }); it('passes rightIcon prop to input', () => { const onValueChange = jest.fn(); const source: any[] = []; - const rightIcon = ; + const rightIcon = ; const props = { value: 'hello', onValueChange, source, rightIcon }; render(); - expect(document.querySelector('.my-testy-icon')).toBeInTheDocument(); + expect(screen.getByTestId('my-testy-icon')).toBeInTheDocument(); }); it('passes id prop to input', () => { @@ -219,36 +219,37 @@ describe('', () => { expect(onCut).toHaveBeenCalledTimes(1); }); - it('passes onInput prop to input', () => { + it('passes onInput prop to input', async () => { const onInput = jest.fn(); const onValueChange = () => undefined; const source: any[] = []; const props = { value: 'hello', onValueChange, source, onInput }; render(); - userEvent.type(screen.getByRole('textbox'), 'a'); + await userEvent.type(screen.getByRole('textbox'), 'a'); expect(onInput).toHaveBeenCalledTimes(1); }); - it('passes onKeyUp prop to input', () => { + it('passes onKeyUp prop to input', async () => { const onKeyUp = jest.fn(); const onValueChange = () => undefined; const source: any[] = []; const props = { value: 'hello', onValueChange, source, onKeyUp }; render(); - userEvent.type(screen.getByRole('textbox'), 'a'); + await userEvent.type(screen.getByRole('textbox'), 'a'); expect(onKeyUp).toHaveBeenCalledTimes(1); }); - it('passes onPaste prop to input', () => { + it('passes onPaste prop to input', async () => { const onPaste = jest.fn(); const onValueChange = () => undefined; const source: any[] = []; const props = { value: 'hello', onValueChange, source, onPaste }; render(); - userEvent.paste(screen.getByRole('textbox'), 'text'); + await userEvent.click(screen.getByRole('textbox')); + await userEvent.paste('text'); expect(onPaste).toHaveBeenCalledTimes(1); }); @@ -285,21 +286,21 @@ describe('', () => { expect(onMouseOver).toHaveBeenCalledTimes(1); }); - it('handles onKeyDown prop', () => { + it('handles onKeyDown prop', async () => { const onValueChange = () => undefined; const onKeyDown = jest.fn(); const source: any[] = []; const props = { value: 'hello', onValueChange, source, onKeyDown }; render(); - userEvent.type(screen.getByRole('textbox'), 'a'); + await userEvent.type(screen.getByRole('textbox'), 'a'); expect(onKeyDown).toHaveBeenCalledTimes(1); const [event] = onKeyDown.mock.calls[0]; expect(event.key).toBe('a'); }); - it('should clear the value when an empty string passed', () => { + it('should clear the value when an empty string passed', async () => { const Comp = () => { const [value, setValue] = useState(''); @@ -316,13 +317,13 @@ describe('', () => { const input = screen.getByRole('textbox'); expect(input).toHaveValue(''); - userEvent.type(input, 'abc'); + await userEvent.type(input, 'abc'); expect(input).toHaveValue('abc'); - userEvent.click(screen.getByRole('button', { name: 'Clear' })); + await userEvent.click(screen.getByRole('button', { name: 'Clear' })); expect(input).toHaveValue(''); - userEvent.type(input, 'a'); + await userEvent.type(input, 'a'); expect(input).toHaveValue('a'); }); @@ -357,7 +358,7 @@ describe('', () => { render(); const input = screen.getByTestId(InputDataTids.root); - userEvent.type(input, 'one'); + await userEvent.type(input, 'one'); expect(input).toHaveAttribute('aria-controls', expect.stringContaining(AutocompleteIds.menu)); await waitFor(() => { diff --git a/packages/react-ui/components/Button/__tests__/Button-test.tsx b/packages/react-ui/components/Button/__tests__/Button-test.tsx index 0c326352206..b15169c3feb 100644 --- a/packages/react-ui/components/Button/__tests__/Button-test.tsx +++ b/packages/react-ui/components/Button/__tests__/Button-test.tsx @@ -23,53 +23,53 @@ describe('Button', () => { const onClick = jest.fn(); render(; } diff --git a/packages/react-ui/components/ComboBox/__tests__/ComboBox-test.tsx b/packages/react-ui/components/ComboBox/__tests__/ComboBox-test.tsx index 4caa7483305..0831500b198 100644 --- a/packages/react-ui/components/ComboBox/__tests__/ComboBox-test.tsx +++ b/packages/react-ui/components/ComboBox/__tests__/ComboBox-test.tsx @@ -2,7 +2,7 @@ /* eslint-disable react/display-name */ /* eslint-disable react/no-unstable-nested-components */ import React, { useState } from 'react'; -import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { MobilePopupDataTids } from '../../../internal/MobilePopup'; @@ -40,6 +40,10 @@ function searchFactory(promise: Promise): [jest.Mock return promise; }); + promise.catch((error) => { + console.error(error); + }); + return [search, searchPromise]; } @@ -56,24 +60,24 @@ describe('ComboBox', () => { expect(() => render( Promise.resolve([])} />)).not.toThrow(); }); - it('focuses on click to input', () => { + it('focuses on click to input', async () => { render( Promise.resolve([])} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); expect(screen.getByRole('textbox')).toHaveFocus(); }); - it('fetches item when focused', () => { + it('fetches item when focused', async () => { const search = jest.fn(() => Promise.resolve([])); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); expect(search).toHaveBeenCalledWith(''); }); - it('fetches items on input', () => { + it('fetches items on input', async () => { const search = jest.fn(() => Promise.resolve([])); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); fireEvent.change(screen.getByRole('textbox'), { target: { value: 'world' } }); expect(search).toHaveBeenCalledTimes(2); @@ -84,7 +88,7 @@ describe('ComboBox', () => { const [search, promise] = searchFactory(Promise.resolve(testValues)); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; expect(screen.queryAllByTestId(ComboBoxMenuDataTids.item)).toHaveLength(testValues.length); @@ -95,7 +99,7 @@ describe('ComboBox', () => { const [search, promise] = searchFactory(Promise.resolve(items)); render( x} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; expect(screen.queryAllByTestId(ComboBoxMenuDataTids.item)).toHaveLength(items.length); @@ -110,7 +114,7 @@ describe('ComboBox', () => { const [search, promise] = searchFactory(Promise.resolve(items)); const onValueChange = jest.fn(); render( x} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; const clickedItemIndex = 0; @@ -126,10 +130,10 @@ describe('ComboBox', () => { const [search, promise] = searchFactory(Promise.resolve(items)); const onValueChange = jest.fn(); render( x} value={'one'} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; - userEvent.type(screen.getByRole('textbox'), '{enter}'); + await userEvent.type(screen.getByRole('textbox'), '{enter}'); expect(onValueChange).toHaveBeenCalledWith('one'); expect(onValueChange).toHaveBeenCalledTimes(1); @@ -139,9 +143,9 @@ describe('ComboBox', () => { const items = ['one', 'two', 'three']; const [search, promise] = searchFactory(Promise.resolve(items)); render( x} value={'one'} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); - userEvent.keyboard('{enter}'); - userEvent.keyboard('{arrowdown}'); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.keyboard('{enter}'); + await userEvent.keyboard('{arrowdown}'); await promise; expect(screen.queryAllByTestId(ComboBoxMenuDataTids.item)).toHaveLength(items.length); @@ -149,13 +153,13 @@ describe('ComboBox', () => { it('retries request on Enter if rejected', async () => { const [search, promise] = searchFactory(Promise.reject()); - render( x} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + render( x.label} />); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; await delay(100); - userEvent.type(screen.getByRole('textbox'), '{enter}'); + await userEvent.type(screen.getByRole('textbox'), '{enter}'); await delay(0); @@ -188,13 +192,13 @@ describe('ComboBox', () => { it('keeps focus after a click on the refresh button', async () => { const [search, promise] = searchFactory(Promise.reject()); - render( x} />); + render( x.label} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; expect(screen.getByTestId(MenuMessageDataTids.root)).toBeInTheDocument(); - userEvent.click(screen.getByTestId(MenuItemDataTids.root)); + await userEvent.click(screen.getByTestId(MenuItemDataTids.root)); await delay(0); expect(search).toHaveBeenCalledTimes(2); @@ -206,10 +210,10 @@ describe('ComboBox', () => { const onUnexpectedInput = jest.fn(); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; - userEvent.type(screen.getByRole('textbox'), 'one'); + await userEvent.type(screen.getByRole('textbox'), 'one'); await promise; @@ -229,25 +233,25 @@ describe('ComboBox', () => { .mockImplementationOnce(() => undefined as unknown as string); render( Promise.resolve([])} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(0); - userEvent.type(screen.getByRole('textbox'), 'one'); + await userEvent.type(screen.getByRole('textbox'), 'one'); clickOutside(); await delay(0); expect(mockFn).toHaveBeenCalledWith('one'); expect(mockFn).toHaveReturnedWith(null); expect(onValueChange).toHaveBeenCalledWith(null); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); - userEvent.type(screen.getByRole('textbox'), 'one'); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.type(screen.getByRole('textbox'), 'one'); await delay(0); clickOutside(); await delay(0); expect(mockFn).toHaveReturnedWith('one'); expect(onValueChange).toHaveBeenCalledWith('one'); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); - userEvent.type(screen.getByRole('textbox'), 'one'); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.type(screen.getByRole('textbox'), 'one'); await delay(0); clickOutside(); await delay(0); @@ -256,11 +260,11 @@ describe('ComboBox', () => { expect(onValueChange).not.toHaveBeenCalledWith(undefined); }); - it('calls onFocus on focus', () => { + it('calls onFocus on focus', async () => { const onFocus = jest.fn(); render( Promise.resolve([])} />); - userEvent.tab(); + await userEvent.tab(); expect(onFocus).toHaveBeenCalledTimes(1); }); @@ -275,7 +279,7 @@ describe('ComboBox', () => { }); it('calls onBlur on click outside when menu is open', async () => { - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; expect(screen.getByTestId(ComboBoxMenuDataTids.item)).toBeInTheDocument(); @@ -287,9 +291,10 @@ describe('ComboBox', () => { }); it('calls onBlur on input blur when menu is closed', async () => { - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); - userEvent.type(screen.getByRole('textbox'), '{esc}'); - + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + act(() => { + fireEvent.keyDown(screen.getByRole('textbox'), { key: 'Escape', code: 'Escape' }); + }); expect(screen.queryByTestId(MenuDataTids.root)).not.toBeInTheDocument(); fireEvent.blur(screen.getByRole('textbox')); @@ -305,7 +310,7 @@ describe('ComboBox', () => { const [search, promise] = searchFactory(Promise.resolve(items)); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; expect(screen.getByTestId(MenuDataTids.root)).toBeInTheDocument(); @@ -322,10 +327,10 @@ describe('ComboBox', () => { const onValueChange = jest.fn(); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; - userEvent.click(screen.getByText('Hello, world')); + await userEvent.click(screen.getByText('Hello, world')); expect(onValueChange).toHaveBeenCalledTimes(1); expect(onValueChange).toHaveBeenCalledWith({ id: 'hello', @@ -345,10 +350,10 @@ describe('ComboBox', () => { render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; - userEvent.click(screen.getByText('Hello, world')); + await userEvent.click(screen.getByText('Hello, world')); expect(onClick).toHaveBeenCalledTimes(1); }); @@ -357,7 +362,7 @@ describe('ComboBox', () => { const [search, promise] = searchFactory(Promise.resolve([])); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; const input = screen.getByRole('textbox'); @@ -375,12 +380,12 @@ describe('ComboBox', () => { it('clear input value if onUnexpectedInput return null', async () => { render( null} getItems={() => Promise.resolve([])} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); fireEvent.change(screen.getByRole('textbox'), { target: { value: 'foo' } }); - - clickOutside(); - await delay(0); + act(() => { + clickOutside(); + }); expect(screen.getByRole('textbox')).toHaveTextContent(''); }); @@ -389,7 +394,7 @@ describe('ComboBox', () => { const [search] = searchFactory(delay(500).then(() => [])); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(300); expect(screen.getByTestId(SpinnerDataTids.root)).toBeInTheDocument(); @@ -412,7 +417,7 @@ describe('ComboBox', () => { const [search, promise] = searchFactory(Promise.resolve(items)); render( x} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; const menuItems = screen.getAllByTestId(ComboBoxMenuDataTids.item); @@ -424,7 +429,7 @@ describe('ComboBox', () => { const [search, promise] = searchFactory(Promise.resolve(items)); render( x} value={'one'} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; const menuItems = screen.getAllByTestId(ComboBoxMenuDataTids.item); @@ -463,22 +468,22 @@ describe('ComboBox', () => { describe('keep edited input text when value changes', () => { const value = { value: 1, label: 'one' }; - it('in default mode', () => { + it('in default mode', async () => { const { rerender } = render( Promise.resolve([value])} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); fireEvent.change(screen.getByRole('textbox'), { target: { value: 'two' } }); clickOutside(); rerender( Promise.resolve([value])} />); - userEvent.click(screen.getByRole('textbox')); + await userEvent.click(screen.getByRole('textbox')); expect(screen.getByRole('textbox')).toHaveValue('two'); }); - it('in autocomplete mode', () => { + it('in autocomplete mode', async () => { const { rerender } = render( Promise.resolve([value])} />, ); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); fireEvent.change(screen.getByRole('textbox'), { target: { value: 'two' } }); clickOutside(); @@ -486,7 +491,7 @@ describe('ComboBox', () => { Promise.resolve([value])} />, ); - userEvent.click(screen.getByRole('textbox')); + await userEvent.click(screen.getByRole('textbox')); expect(screen.getByRole('textbox')).toHaveValue('two'); }); }); @@ -496,17 +501,17 @@ describe('ComboBox', () => { const getItems = jest.fn(); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(0); expect(getItems).toHaveBeenCalledTimes(0); expect(screen.queryByTestId(ComboBoxMenuDataTids.items)).not.toBeInTheDocument(); }); - it('reset', () => { + it('reset', async () => { render( Promise.resolve([])} ref={comboboxRef} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); fireEvent.change(screen.getByRole('textbox'), { target: { value: 'foo' } }); expect(screen.getByRole('textbox')).toHaveValue('foo'); @@ -529,7 +534,7 @@ describe('ComboBox', () => { const changeHandler = jest.fn(); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); fireEvent.change(screen.getByRole('textbox'), { target: { value: testValues[1].label } }); @@ -610,20 +615,22 @@ describe('ComboBox', () => { beforeEach(async () => { render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); delay(0); onFocus.mockClear(); onBlur.mockClear(); }); it('click on item', async () => { - userEvent.click(screen.getAllByTestId(ComboBoxMenuDataTids.item)[0]); + await userEvent.click(screen.getAllByTestId(ComboBoxMenuDataTids.item)[0]); await delay(0); // await for restore focus expect(screen.getByRole('textbox')).toHaveFocus(); // input text is not selected + // eslint-disable-next-line testing-library/no-node-access expect((document.activeElement as HTMLInputElement).selectionStart).toBe( + // eslint-disable-next-line testing-library/no-node-access (document.activeElement as HTMLInputElement).selectionEnd, ); @@ -632,15 +639,17 @@ describe('ComboBox', () => { }); it('Enter on item', async () => { - userEvent.keyboard('{arrowdown}'); - userEvent.keyboard('{enter}'); + await userEvent.keyboard('{arrowdown}'); + await userEvent.keyboard('{enter}'); await delay(0); expect(screen.getByRole('textbox')).toHaveFocus(); // input text is not selected + // eslint-disable-next-line testing-library/no-node-access expect((document.activeElement as HTMLInputElement).selectionStart).toBe( + // eslint-disable-next-line testing-library/no-node-access (document.activeElement as HTMLInputElement).selectionEnd, ); @@ -655,7 +664,7 @@ describe('ComboBox', () => { describe('in default mode', () => { beforeEach(async () => { render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); getItems.mockClear(); }); @@ -664,50 +673,50 @@ describe('ComboBox', () => { expect(screen.queryByTestId(MenuDataTids.root)).not.toBeInTheDocument(); - userEvent.click(screen.getByRole('textbox')); + await userEvent.click(screen.getByRole('textbox')); await delay(0); expect(screen.getByTestId(MenuDataTids.root)).toBeInTheDocument(); expect(screen.getAllByTestId(ComboBoxMenuDataTids.item)).toHaveLength(testValues.length); }); - it('runs empty search if menu is closed', () => { + it('runs empty search if menu is closed', async () => { comboboxRef.current?.close(); delay(0); expect(screen.queryByTestId(MenuDataTids.root)).not.toBeInTheDocument(); - userEvent.click(screen.getByRole('textbox')); + await userEvent.click(screen.getByRole('textbox')); expect(getItems).toHaveBeenCalledWith(''); }); - it("doesn't run search if menu is open", () => { - userEvent.click(screen.getByRole('textbox')); + it("doesn't run search if menu is open", async () => { + await userEvent.click(screen.getByRole('textbox')); expect(getItems).toHaveBeenCalledTimes(0); }); }); describe('in autocomplete mode', () => { - beforeEach(() => { + beforeEach(async () => { render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); getItems.mockClear(); }); - it("doesn't open menu if it is closed", () => { + it("doesn't open menu if it is closed", async () => { comboboxRef.current?.close(); - userEvent.click(screen.getByRole('textbox')); + await userEvent.click(screen.getByRole('textbox')); expect(screen.queryByTestId(MenuDataTids.root)).not.toBeInTheDocument(); }); - it("doesn't run search if menu is closed", () => { + it("doesn't run search if menu is closed", async () => { comboboxRef.current?.close(); - userEvent.click(screen.getByRole('textbox')); + await userEvent.click(screen.getByRole('textbox')); expect(getItems).toHaveBeenCalledTimes(0); }); - it("doesn't run search if menu is open", () => { - userEvent.click(screen.getByRole('textbox')); + it("doesn't run search if menu is open", async () => { + await userEvent.click(screen.getByRole('textbox')); expect(getItems).toHaveBeenCalledTimes(0); }); }); @@ -994,7 +1003,7 @@ describe('ComboBox', () => { }); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(300); expect(screen.getByTestId(SpinnerDataTids.root)).toBeInTheDocument(); @@ -1003,7 +1012,7 @@ describe('ComboBox', () => { expect(screen.queryByTestId(SpinnerDataTids.root)).not.toBeInTheDocument(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(300); expect(screen.getByTestId(SpinnerDataTids.root)).toBeInTheDocument(); @@ -1016,7 +1025,7 @@ describe('ComboBox', () => { }); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(600); expect(screen.getByTestId(SpinnerDataTids.root)).toBeInTheDocument(); @@ -1026,7 +1035,7 @@ describe('ComboBox', () => { expect(screen.queryByTestId(SpinnerDataTids.root)).not.toBeInTheDocument(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(300); expect(screen.getByTestId(SpinnerDataTids.root)).toBeInTheDocument(); @@ -1040,7 +1049,7 @@ describe('ComboBox', () => { [search, promise] = searchFactory(Promise.resolve(null)); }); const focus = async (): Promise => { - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; }; @@ -1113,7 +1122,7 @@ describe('ComboBox', () => { }); }); - it.each(['', null, undefined])('should clear the value when %s passed', (testValue) => { + it.each(['', null, undefined])('should clear the value when %s passed', async (testValue) => { const Comp = () => { const [value, setValue] = useState({ value: 1, label: 'First' }); @@ -1134,7 +1143,7 @@ describe('ComboBox', () => { const input = screen.getByTestId('InputLikeText__input'); expect(input).toHaveTextContent(/^First$/); - userEvent.click(screen.getByRole('button', { name: 'Clear' })); + await userEvent.click(screen.getByRole('button', { name: 'Clear' })); expect(input).toHaveTextContent(''); }); @@ -1197,10 +1206,11 @@ describe('ComboBox', () => { const addNewElement = async () => { render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); - userEvent.type(screen.getByRole('textbox'), 'newItem'); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.clear(screen.getByRole('textbox')); + await userEvent.type(screen.getByRole('textbox'), 'newItem'); await delay(0); - userEvent.click(screen.getByTestId('addButton')); + await userEvent.click(screen.getByTestId('addButton')); }; it('add new element', async () => { @@ -1210,13 +1220,13 @@ describe('ComboBox', () => { it('show added item after blur', async () => { await addNewElement(); - userEvent.click(screen.getByRole('textbox')); + await userEvent.click(screen.getByRole('textbox')); await delay(0); expect(screen.getAllByTestId(ComboBoxMenuDataTids.item)).toHaveLength(4); clickOutside(); await delay(0); expect(screen.queryByTestId(ComboBoxMenuDataTids.item)).not.toBeInTheDocument(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(0); expect(screen.getAllByTestId(ComboBoxMenuDataTids.item)).toHaveLength(4); }); @@ -1229,7 +1239,7 @@ describe('ComboBox', () => { { value: 2, label: 'Second' }, ]; - const itemWrapper = (item?: { value: number; label: string }) => { + const itemWrapper = (item: { value: number; label: string }) => { if (item?.value === 2) { return (props: HTMLProps['a']) => ; } @@ -1244,7 +1254,7 @@ describe('ComboBox', () => { render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(0); expect(screen.getByRole('button', { name: 'First' })).toBeInTheDocument(); expect(screen.getByRole('link', { name: 'Second' })).toBeInTheDocument(); @@ -1293,7 +1303,7 @@ describe('ComboBox', () => { expect.stringContaining(ComboBoxViewIds.menu), ); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); expect(screen.getByTestId(InputDataTids.root)).toHaveAttribute( 'aria-controls', @@ -1308,11 +1318,11 @@ describe('ComboBox', () => { }); }); - it('sets value for aria-label attribute', () => { + it('sets value for aria-label attribute', async () => { const ariaLabel = 'aria-label'; render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); expect(screen.getByRole('textbox')).toHaveAttribute('aria-label', ariaLabel); }); @@ -1368,10 +1378,10 @@ describe('ComboBox', () => { render(); comboboxRef.current?.focus(); expect(screen.getByRole('textbox')).toHaveValue(initialValue.label); - userEvent.clear(screen.getByRole('textbox')); + await userEvent.clear(screen.getByRole('textbox')); expect(await screen.findByRole('textbox')).toHaveValue(''); - userEvent.click(screen.getByRole('button', { name: 'Обновить' })); + await userEvent.click(screen.getByRole('button', { name: 'Обновить' })); expect(await screen.findByRole('textbox')).toHaveValue(expectedValue.label); }); @@ -1431,7 +1441,7 @@ describe('mobile comboBox', () => { it('should fully close by method', async () => { render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(500); close(); @@ -1441,12 +1451,12 @@ describe('mobile comboBox', () => { it('should close and open again after being closed by public method', async () => { render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(500); close(); - userEvent.click(screen.getByTestId(InputDataTids.root)); + await userEvent.click(screen.getByTestId(InputDataTids.root)); await delay(500); expect(screen.getByTestId(MobilePopupDataTids.root)).toBeInTheDocument(); diff --git a/packages/react-ui/components/CurrencyInput/CurrencyInput.tsx b/packages/react-ui/components/CurrencyInput/CurrencyInput.tsx index b888899716a..584580e30db 100644 --- a/packages/react-ui/components/CurrencyInput/CurrencyInput.tsx +++ b/packages/react-ui/components/CurrencyInput/CurrencyInput.tsx @@ -155,7 +155,7 @@ export class CurrencyInput extends React.PureComponent + {this.renderMain} ); diff --git a/packages/react-ui/components/CurrencyInput/__tests__/CurrencyInput-test.tsx b/packages/react-ui/components/CurrencyInput/__tests__/CurrencyInput-test.tsx index d58fa794d0b..c47b529bfe8 100644 --- a/packages/react-ui/components/CurrencyInput/__tests__/CurrencyInput-test.tsx +++ b/packages/react-ui/components/CurrencyInput/__tests__/CurrencyInput-test.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { fireEvent, render, screen } from '@testing-library/react'; +import { act, fireEvent, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { CurrencyInput } from '../CurrencyInput'; @@ -29,6 +29,12 @@ const CurrencyInputAndButton = (props: { value: unknown }): JSX.Element => { ); }; +const clearInput = async (input: Element) => { + for (let i = 0; i < 5; i++) { + await userEvent.type(input, '{backspace}'); + } +}; + describe('CurrencyInput', () => { it('should mount with a number value', () => { render(); @@ -59,36 +65,41 @@ describe('CurrencyInput', () => { expect(input).toHaveValue(''); }); - it('should set a correct number value', () => { + it('should set a correct number value', async () => { render(); const input = screen.getByRole('textbox'); - userEvent.clear(input); - userEvent.type(input, '123'); - input.blur(); + await clearInput(input); + await userEvent.type(input, '123'); + act(() => { + input.blur(); + }); expect(input).toHaveValue('123,00'); }); - it('should not set a string value', () => { + it('should not set a string value', async () => { render(); const input = screen.getByRole('textbox'); - userEvent.clear(input); - userEvent.type(input, 'str'); - input.blur(); + await clearInput(input); + await userEvent.type(input, 'str'); + act(() => { + input.blur(); + }); expect(input).toHaveValue(''); }); - it('should change value with a valid number', () => { + it('should change value with a valid number', async () => { render(); const button = screen.getByRole('button'); - userEvent.click(button); + await userEvent.click(button); const input = screen.getByRole('textbox'); expect(input).toHaveValue('123,00'); }); - it('should change value and not throw an error with a valid string', () => { - render(); + it('should change value and not throw an error with a valid string', async () => { + render(); const button = screen.getByRole('button'); expect(() => userEvent.click(button)).not.toThrow(); + await userEvent.click(button); const input = screen.getByRole('textbox'); expect(input).toHaveValue('123,00'); }); @@ -109,7 +120,7 @@ describe('CurrencyInput', () => { expect(input).toHaveValue('12,00'); }); - it('should clear `value` in input when undefined passed', () => { + it('should clear `value` in input when undefined passed', async () => { const Comp = () => { const [value, setValue] = useState>(12345); return ( @@ -121,11 +132,11 @@ describe('CurrencyInput', () => { }; render(); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(screen.getByRole('textbox')).toHaveValue(''); }); - it('should clear `value` in input when null passed', () => { + it('should clear `value` in input when null passed', async () => { const Comp = () => { const [value, setValue] = useState>(12345); return ( @@ -137,7 +148,7 @@ describe('CurrencyInput', () => { }; render(); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(screen.getByRole('textbox')).toHaveValue(''); }); @@ -149,7 +160,9 @@ describe('CurrencyInput', () => { }; render(); - currencyInputRef.current?.focus(); + act(() => { + currencyInputRef.current?.focus(); + }); expect(screen.getByRole('textbox')).toHaveFocus(); }); @@ -161,7 +174,9 @@ describe('CurrencyInput', () => { return ; }; render(); - currencyInputRef.current?.focus(); + act(() => { + currencyInputRef.current?.focus(); + }); expect(screen.getByRole('textbox')).toHaveFocus(); expect(onFocus).toHaveBeenCalled(); }); @@ -173,9 +188,13 @@ describe('CurrencyInput', () => { return ; }; render(); - screen.getByRole('textbox').focus(); + act(() => { + screen.getByRole('textbox').focus(); + }); expect(screen.getByRole('textbox')).toHaveFocus(); - currencyInputRef.current?.blur(); + act(() => { + currencyInputRef.current?.blur(); + }); expect(screen.getByRole('textbox')).not.toHaveFocus(); }); @@ -189,19 +208,21 @@ describe('CurrencyInput', () => { render(); screen.getByRole('textbox').focus(); expect(screen.getByRole('textbox')).toHaveFocus(); - currencyInputRef.current?.blur(); + act(() => { + currencyInputRef.current?.blur(); + }); expect(screen.getByRole('textbox')).not.toHaveFocus(); expect(onBlur).toHaveBeenCalled(); }); - it('should handle onKeyDown event', () => { + it('should handle onKeyDown event', async () => { const onKeyDown = jest.fn(); const Comp = () => { const [value, setValue] = useState>(12345); return ; }; render(); - userEvent.type(screen.getByRole('textbox'), '{enter}'); + await userEvent.type(screen.getByRole('textbox'), '{enter}'); expect(onKeyDown).toHaveBeenCalledTimes(1); }); @@ -212,7 +233,7 @@ describe('CurrencyInput', () => { return ; }; - it('should handle cursor Backspace move key down correctly', () => { + it('should handle cursor Backspace move key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 4; @@ -220,15 +241,15 @@ describe('CurrencyInput', () => { fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - userEvent.keyboard('{backspace}'); - userEvent.keyboard('{backspace}'); + await userEvent.keyboard('{backspace}'); + await userEvent.keyboard('{backspace}'); //should be on 1 position due to the automatic ⎵ between 12 and 300 expect(input.selectionStart).toBe(1); expect(input.selectionEnd).toBe(1); }); - it('should handle cursor right move key down correctly', () => { + it('should handle cursor right move key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 0; @@ -236,15 +257,15 @@ describe('CurrencyInput', () => { fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - userEvent.keyboard('{arrowright}'); - userEvent.keyboard('{arrowright}'); + await userEvent.keyboard('{arrowright}'); + await userEvent.keyboard('{arrowright}'); //should be on 3 position due to the automatic ⎵ between 12 and 300 expect(input.selectionStart).toBe(3); expect(input.selectionEnd).toBe(3); }); - it('should handle cursor left move key down correctly', () => { + it('should handle cursor left move key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 4; @@ -252,15 +273,15 @@ describe('CurrencyInput', () => { fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - userEvent.keyboard('{arrowleft}'); - userEvent.keyboard('{arrowleft}'); + await userEvent.keyboard('{arrowleft}'); + await userEvent.keyboard('{arrowleft}'); //should be on 1 position due to the automatic ⎵ between 12 and 300 expect(input.selectionStart).toBe(1); expect(input.selectionEnd).toBe(1); }); - it('should handle move to start key down correctly', () => { + it('should handle move to start key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 4; @@ -268,13 +289,13 @@ describe('CurrencyInput', () => { fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - userEvent.keyboard('{home}'); + await userEvent.keyboard('{home}'); expect(input.selectionStart).toBe(0); expect(input.selectionEnd).toBe(0); }); - it('should handle move to end key down correctly', () => { + it('should handle move to end key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 4; @@ -282,28 +303,27 @@ describe('CurrencyInput', () => { fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - userEvent.keyboard('{end}'); + fireEvent.keyDown(input, { key: 'End', code: 'End' }); expect(input.selectionStart).toBe(input.value?.length); expect(input.selectionEnd).toBe(input.value?.length); }); - it('should handle selection left extension key down correctly', () => { + it('should handle selection left extension key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 4; - fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - - userEvent.keyboard('{shift}{arrowleft/}{arrowleft/}{/shift}'); + fireEvent.keyDown(input, { key: 'ArrowLeft', code: 'ArrowLeft', shiftKey: true }); + fireEvent.keyDown(input, { key: 'ArrowLeft', code: 'ArrowLeft', shiftKey: true }); //should be selected from 1 position due to the automatic ⎵ between 12 and 300 expect(input.selectionStart).toBe(1); - expect(input.selectionEnd).toBe(startCursorPosition); + expect(input.selectionEnd).toBe(4); }); - it('should handle selection right extension key down correctly', () => { + it('should handle selection right extension key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 0; @@ -311,14 +331,14 @@ describe('CurrencyInput', () => { fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - userEvent.keyboard('{shift}{arrowright/}{arrowright/}{/shift}'); - + fireEvent.keyDown(input, { key: 'ArrowRight', code: 'ArrowRight', shiftKey: true }); + fireEvent.keyDown(input, { key: 'ArrowRight', code: 'ArrowRight', shiftKey: true }); //should be selected till 3 position due to the automatic ⎵ between 12 and 300 expect(input.selectionStart).toBe(startCursorPosition); expect(input.selectionEnd).toBe(3); }); - it('should handle full selection key down correctly', () => { + it('should handle full selection key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 0; @@ -326,13 +346,13 @@ describe('CurrencyInput', () => { fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - userEvent.keyboard('{ctrl}a{/ctrl}'); + fireEvent.keyDown(input, { key: 'a', code: 'KeyA', ctrlKey: true }); expect(input.selectionStart).toBe(startCursorPosition); expect(input.selectionEnd).toBe(input.value?.length); }); - it('should handle selection to start key down correctly', () => { + it('should handle selection to start key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 4; @@ -340,13 +360,13 @@ describe('CurrencyInput', () => { fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - userEvent.keyboard('{shift}{home/}{/shift}'); + fireEvent.keyDown(input, { key: 'Home', code: 'Home', shiftKey: true }); expect(input.selectionStart).toBe(0); expect(input.selectionEnd).toBe(startCursorPosition); }); - it('should handle selection to end key down correctly', () => { + it('should handle selection to end key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 4; @@ -354,7 +374,7 @@ describe('CurrencyInput', () => { fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - userEvent.keyboard('{shift}{end/}{/shift}'); + fireEvent.keyDown(input, { key: 'End', code: 'End', shiftKey: true }); expect(input.selectionStart).toBe(startCursorPosition); expect(input.selectionEnd).toBe(input.value?.length); @@ -369,12 +389,14 @@ describe('CurrencyInput', () => { ['IntlBackslash', '1,23'], ['NumpadDivide', '1,23'], ])('should applied [%s] as comma', (delimiter, expected) => { - it(`return: ${expected}`, () => { + it(`return: ${expected}`, async () => { render(); const input = screen.getByRole('textbox'); - userEvent.clear(input); - userEvent.keyboard(`1[${delimiter}]23`, {}); - input.blur(); + await clearInput(input); + await userEvent.keyboard(`1[${delimiter}]23`, {}); + act(() => { + input.blur(); + }); expect(input).toHaveValue(expected); }); }); diff --git a/packages/react-ui/components/DateInput/__tests__/DateInput-test.tsx b/packages/react-ui/components/DateInput/__tests__/DateInput-test.tsx index 86880153155..42786b4ac2d 100644 --- a/packages/react-ui/components/DateInput/__tests__/DateInput-test.tsx +++ b/packages/react-ui/components/DateInput/__tests__/DateInput-test.tsx @@ -118,11 +118,11 @@ describe('DateInput as InputlikeText', () => { KeyDownCases.forEach(([initDate, keys, expected]) => { const keyString = keys.join(' > '); const expectedDateStr = `"${expected}"`.padEnd(12, ' '); - it(`calls onValueChange with ${expectedDateStr} if value is "${initDate}" and pressed "${keyString}"`, () => { + it(`calls onValueChange with ${expectedDateStr} if value is "${initDate}" and pressed "${keyString}"`, async () => { const onValueChange = jest.fn(); render({ value: initDate, onValueChange }); const input = getInput(); - userEvent.click(input); + await userEvent.click(input); keys.forEach((key) => fireEvent.keyDown(input, { key })); @@ -196,11 +196,11 @@ describe('DateInput as InputlikeText', () => { KeyDownCases.forEach(([initDate, keys]) => { const keyString = keys.join(' > '); - it(`does not call onValueChange if value is "${initDate}", minDate is "${minDate}", maxDate is "${maxDate}" and pressed "${keyString}"`, () => { + it(`does not call onValueChange if value is "${initDate}", minDate is "${minDate}", maxDate is "${maxDate}" and pressed "${keyString}"`, async () => { const onValueChange = jest.fn(); render({ value: initDate, onValueChange, minDate, maxDate }); const input = getInput(); - userEvent.click(input); + await userEvent.click(input); keys.forEach((key) => fireEvent.keyDown(input, { key })); expect(onValueChange).not.toHaveBeenCalled(); @@ -224,11 +224,11 @@ describe('DateInput as InputlikeText', () => { const keyString = keys.join(' > '); const expectedDateStr = 'calls onValueChange with ' + `"${expected}"`.padEnd(12, ' '); - it(`${expectedDateStr} if value is "${initDate}", minDate is "${minDate}", maxDate is "${maxDate}" and pressed "${keyString}"`, () => { + it(`${expectedDateStr} if value is "${initDate}", minDate is "${minDate}", maxDate is "${maxDate}" and pressed "${keyString}"`, async () => { const onValueChange = jest.fn(); render({ value: initDate, onValueChange, minDate, maxDate }); const input = getInput(); - userEvent.click(input); + await userEvent.click(input); keys.forEach((key) => fireEvent.keyDown(input, { key })); const [value] = onValueChange.mock.calls[0]; @@ -252,21 +252,21 @@ describe('DateInput as InputlikeText', () => { expect(onKeyDown).toHaveBeenCalled(); }); - it('should handle onFocus event', () => { + it('should handle onFocus event', async () => { const onFocus = jest.fn(); renderRTL(); - userEvent.click(getInput()); + await userEvent.click(getInput()); expect(onFocus).toHaveBeenCalled(); }); - it('should handle onBlur event', () => { + it('should handle onBlur event', async () => { const onBlur = jest.fn(); renderRTL(); - userEvent.tab(); + await userEvent.tab(); expect(screen.getByTestId(InputLikeTextDataTids.root)).toHaveFocus(); - userEvent.tab(); + await userEvent.tab(); expect(screen.getByTestId(InputLikeTextDataTids.root)).not.toHaveFocus(); expect(onBlur).toHaveBeenCalled(); }); @@ -277,7 +277,7 @@ describe('DateInput as InputlikeText', () => { renderRTL(); const input = getInput(); - userEvent.dblClick(input); + await userEvent.dblClick(input); expect(screen.getByTestId(InputLikeTextDataTids.root)).toHaveFocus(); await delay(0); expect(getSelection()?.toString()).toBe(value); @@ -287,30 +287,30 @@ describe('DateInput as InputlikeText', () => { 2, )}.${MASK_CHAR_EXEMPLAR.repeat(4)}`; - it('should clear selected text in the input after pressing delete button', () => { + it('should clear selected text in the input after pressing delete button', async () => { renderRTL(); const input = getInput(); - userEvent.dblClick(input); - userEvent.keyboard('{delete}'); + await userEvent.dblClick(input); + await userEvent.keyboard('{delete}'); // eslint-disable-next-line jest-dom/prefer-to-have-text-content expect(input.textContent).toBe(textContentWithMaskChars); }); - it('should clear selected text in the input after pressing backspace button', () => { + it('should clear selected text in the input after pressing backspace button', async () => { renderRTL(); const input = getInput(); - userEvent.dblClick(input); - userEvent.keyboard('{backspace}'); + await userEvent.dblClick(input); + await userEvent.keyboard('{backspace}'); // eslint-disable-next-line jest-dom/prefer-to-have-text-content expect(input.textContent).toBe(textContentWithMaskChars); }); - it('should delete one char in DD by default after focus on element', () => { + it('should delete one char in DD by default after focus on element', async () => { renderRTL(); const input = getInput(); - userEvent.type(input, '{backspace}'); + await userEvent.type(input, '{backspace}'); // eslint-disable-next-line jest-dom/prefer-to-have-text-content expect(input.textContent).toBe(`2${MASK_CHAR_EXEMPLAR.repeat(1)}.04.1988`); @@ -336,7 +336,7 @@ describe('DateInput as InputlikeText', () => { expect(screen.getByTestId(InputLikeTextDataTids.root)).not.toHaveFocus(); }); - it('blink method works', () => { + it('blink method works', async () => { const blinkMock = jest.fn(); const inputLikeTextRef = React.createRef(); renderRTL(); @@ -344,7 +344,7 @@ describe('DateInput as InputlikeText', () => { if (inputLikeTextRef.current) { inputLikeTextRef.current.blink = blinkMock; } - userEvent.type(getInput(), '{enter}'); + await userEvent.type(getInput(), '{enter}'); expect(blinkMock).toHaveBeenCalledTimes(1); }); diff --git a/packages/react-ui/components/DatePicker/DatePicker.tsx b/packages/react-ui/components/DatePicker/DatePicker.tsx index fa6fa5df80d..eb9a647468d 100644 --- a/packages/react-ui/components/DatePicker/DatePicker.tsx +++ b/packages/react-ui/components/DatePicker/DatePicker.tsx @@ -254,7 +254,7 @@ export class DatePicker extends React.PureComponent - + {this.renderMain} diff --git a/packages/react-ui/components/DatePicker/__tests__/DatePicker-test.tsx b/packages/react-ui/components/DatePicker/__tests__/DatePicker-test.tsx index 60862877a3b..8b484c0497d 100644 --- a/packages/react-ui/components/DatePicker/__tests__/DatePicker-test.tsx +++ b/packages/react-ui/components/DatePicker/__tests__/DatePicker-test.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { render, screen } from '@testing-library/react'; +import { act, render, screen, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { componentsLocales as DateSelectLocalesRu } from '../../../internal/DateSelect/locale/locales/ru'; @@ -39,23 +39,23 @@ describe('DatePicker', () => { expect(screen.getByTestId(DatePickerDataTids.label)).toBeInTheDocument(); }); - it('renders date select when open', () => { + it('renders date select when open', async () => { render(); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId(CalendarDataTids.root)).toBeInTheDocument(); }); - it("doesn't open on focus if disabled", () => { + it("doesn't open on focus if disabled", async () => { render(); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.queryByTestId('Calendar')).not.toBeInTheDocument(); }); - it('closes when become disabled', () => { + it('closes when become disabled', async () => { const { rerender } = render(); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId(CalendarDataTids.root)).toBeInTheDocument(); rerender(); @@ -67,31 +67,32 @@ describe('DatePicker', () => { expect(screen.getByTestId(CalendarDataTids.root)).toBeInTheDocument(); }); - it('blur() methon works', () => { + it('blur() methon works', async () => { const datePickerRef = React.createRef(); render(); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId(CalendarDataTids.root)).toBeInTheDocument(); - - datePickerRef.current?.blur(); + act(() => { + datePickerRef.current?.blur(); + }); expect(screen.queryByTestId(CalendarDataTids.root)).not.toBeInTheDocument(); }); - it('handle onBlur event', () => { + it('handle onBlur event', async () => { const datePickerRef = React.createRef(); const onBlur = jest.fn(); render(); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId(CalendarDataTids.root)).toBeInTheDocument(); datePickerRef.current?.blur(); expect(onBlur).toHaveBeenCalled(); }); - it('handle onFocus event', () => { + it('handle onFocus event', async () => { const onFocus = jest.fn(); render(); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(onFocus).toHaveBeenCalled(); }); @@ -101,17 +102,17 @@ describe('DatePicker', () => { .setComponents(InternalDateGetter.getTodayComponents()) .toString({ withPad: true, withSeparator: true }); - it('render without LocaleProvider', () => { + it('render without LocaleProvider', async () => { render(); const expectedText = DatePickerLocaleHelper.get(defaultLangCode).today; const today = getToday({ langCode: defaultLangCode }); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId('Picker__todayWrapper')).toHaveTextContent(`${expectedText} ${today}`); }); - it('render default locale', () => { + it('render default locale', async () => { render( @@ -120,12 +121,12 @@ describe('DatePicker', () => { const expectedText = DatePickerLocaleHelper.get(defaultLangCode).today; const today = getToday({ langCode: defaultLangCode }); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId('Picker__todayWrapper')).toHaveTextContent(`${expectedText} ${today}`); }); - it('render correct locale when set langCode', () => { + it('render correct locale when set langCode', async () => { render( @@ -135,12 +136,12 @@ describe('DatePicker', () => { const expectedText = DatePickerLocaleHelper.get(LangCodes.en_GB).today; const today = getToday({ langCode: LangCodes.en_GB }); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId('Picker__todayWrapper')).toHaveTextContent(`${expectedText} ${today}`); }); - it('render custom locale', () => { + it('render custom locale', async () => { render( { const expectedText = DatePickerLocaleHelper.get(LangCodes.en_GB).today; const today = getToday({ langCode: LangCodes.en_GB, separator: InternalDateSeparator.Dash }); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId('Picker__todayWrapper')).toHaveTextContent(`${expectedText} ${today}`); }); - it('updates when langCode changes', () => { + it('updates when langCode changes', async () => { const { rerender } = render( @@ -173,12 +174,12 @@ describe('DatePicker', () => { , ); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId('Picker__todayWrapper')).toHaveTextContent(`${expectedText} ${today}`); }); - it('should rename months using locale', () => { + it('should rename months using locale', async () => { const renamedMonths = [ 'one', 'two', @@ -199,12 +200,12 @@ describe('DatePicker', () => { , ); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByText(renamedMonths[6])).toBeInTheDocument(); }); - it.each(['', null, undefined])('should clear the value when %s passed', (testValue) => { + it.each(['', null, undefined])('should clear the value when %s passed', async (testValue) => { const Comp = () => { const [value, setValue] = useState('24.08.2022'); @@ -221,12 +222,12 @@ describe('DatePicker', () => { const input = screen.getByTestId(InputLikeTextDataTids.input); expect(input).toHaveTextContent(/^24.08.2022$/); - userEvent.click(screen.getByRole('button', { name: 'Clear' })); + await userEvent.click(screen.getByRole('button', { name: 'Clear' })); const expected = 'ss.ss.ssss'.replace(/s/g, MASK_CHAR_EXEMPLAR); const expectedRegExp = new RegExp(`^${expected}$`); expect(input).toHaveTextContent(expectedRegExp, { normalizeWhitespace: false }); - userEvent.type(input, '24.08.2022'); + await userEvent.type(input, '24.08.2022'); expect(input).toHaveTextContent(/^24.08.2022$/); }); @@ -238,10 +239,10 @@ describe('DatePicker', () => { }); describe('a11y', () => { - it('sets value for aria-label attribute (ru)', () => { + it('sets value for aria-label attribute (ru)', async () => { render(); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId(DatePickerDataTids.pickerTodayWrapper)).toHaveAttribute( 'aria-label', @@ -249,14 +250,14 @@ describe('DatePicker', () => { ); }); - it('sets value for aria-label attribute (en)', () => { + it('sets value for aria-label attribute (en)', async () => { render( , ); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId(DatePickerDataTids.pickerTodayWrapper)).toHaveAttribute( 'aria-label', @@ -264,7 +265,7 @@ describe('DatePicker', () => { ); }); - it('sets custom value for `todayAriaLabel` locale', () => { + it('sets custom value for `todayAriaLabel` locale', async () => { const customAriaLabel = 'test'; render( @@ -272,11 +273,11 @@ describe('DatePicker', () => { , ); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId(DatePickerDataTids.pickerTodayWrapper)).toHaveAttribute('aria-label', customAriaLabel); }); - it('sets custom value for `selectMonthAriaLabel` locale', () => { + it('sets custom value for `selectMonthAriaLabel` locale', async () => { const customAriaLabel = 'test'; render( @@ -284,15 +285,16 @@ describe('DatePicker', () => { , ); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); - expect(screen.getAllByTestId(CalendarDataTids.headerMonth)[0].querySelector('button')).toHaveAttribute( + const monthButton = within(screen.getAllByTestId(CalendarDataTids.headerMonth)[0]).getByRole('button'); + expect(monthButton).toHaveAttribute( 'aria-label', `${DateSelectLocalesRu.selectChosenAriaLabel} ${customAriaLabel} Февраль`, ); }); - it('sets custom value for `selectYearAriaLabel` locale', () => { + it('sets custom value for `selectYearAriaLabel` locale', async () => { const customAriaLabel = 'test'; render( @@ -300,15 +302,16 @@ describe('DatePicker', () => { , ); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); - expect(screen.getAllByTestId(CalendarDataTids.headerYear)[0].querySelector('button')).toHaveAttribute( + const yearButton = within(screen.getAllByTestId(CalendarDataTids.headerYear)[0]).getByRole('button'); + expect(yearButton).toHaveAttribute( 'aria-label', `${DateSelectLocalesRu.selectChosenAriaLabel} ${customAriaLabel} 2021`, ); }); - it('sets custom value for `selectChosenAriaLabel` locale', () => { + it('sets custom value for `selectChosenAriaLabel` locale', async () => { const customAriaLabel = 'test'; render( @@ -316,15 +319,16 @@ describe('DatePicker', () => { , ); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); - expect(screen.getAllByTestId(CalendarDataTids.headerYear)[0].querySelector('button')).toHaveAttribute( + const yearButton = within(screen.getAllByTestId(CalendarDataTids.headerYear)[0]).getByRole('button'); + expect(yearButton).toHaveAttribute( 'aria-label', `${customAriaLabel} ${DateSelectLocalesRu.selectYearAriaLabel} 2021`, ); }); - it('sets custom value for `dayCellChooseDateAriaLabel` locale', () => { + it('sets custom value for `dayCellChooseDateAriaLabel` locale', async () => { const customAriaLabel = 'test'; const date = '1.2.2021'; render( @@ -333,7 +337,7 @@ describe('DatePicker', () => { , ); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getAllByTestId(CalendarDataTids.dayCell)[0]).toHaveAttribute( 'aria-label', diff --git a/packages/react-ui/components/Dropdown/__stories__/Dropdown.stories.tsx b/packages/react-ui/components/Dropdown/__stories__/Dropdown.stories.tsx index 70733ca10c6..2ef469ee0dc 100644 --- a/packages/react-ui/components/Dropdown/__stories__/Dropdown.stories.tsx +++ b/packages/react-ui/components/Dropdown/__stories__/Dropdown.stories.tsx @@ -15,7 +15,7 @@ import { MenuHeader } from '../../MenuHeader'; export default { title: 'Dropdown', decorators: [ - (Story) => ( + (Story: () => JSX.Element) => (
diff --git a/packages/react-ui/components/Dropdown/__tests__/Dropdown-test.tsx b/packages/react-ui/components/Dropdown/__tests__/Dropdown-test.tsx index 27d19b5faf3..75033341083 100644 --- a/packages/react-ui/components/Dropdown/__tests__/Dropdown-test.tsx +++ b/packages/react-ui/components/Dropdown/__tests__/Dropdown-test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { act, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { Dropdown, DropdownDataTids } from '../Dropdown'; @@ -28,24 +28,24 @@ describe('Dropdown', () => { expect(screen.getByTestId(DropdownDataTids.root)).toBeInTheDocument(); }); - it('Renders items', () => { + it('Renders items', async () => { render({menuItem}); - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); expect(screen.getByText(menuItemText)).toBeInTheDocument(); }); - it('opens and closes', () => { + it('opens and closes', async () => { render({menuItem}); //is menu open check expect(screen.queryByTestId(MenuItemDataTids.root)).not.toBeInTheDocument(); - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); expect(screen.getByTestId(MenuItemDataTids.root)).toBeInTheDocument(); - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); expect(screen.queryByTestId(MenuItemDataTids.root)).not.toBeInTheDocument(); }); @@ -81,7 +81,9 @@ describe('Dropdown', () => { //is menu open check expect(screen.queryByTestId(MenuItemDataTids.root)).not.toBeInTheDocument(); - dropdownRef.current?.open(); + act(() => { + dropdownRef.current?.open(); + }); expect(screen.getByTestId(MenuItemDataTids.root)).toBeInTheDocument(); }); @@ -95,11 +97,13 @@ describe('Dropdown', () => { ); //is menu open check expect(screen.queryByTestId(MenuItemDataTids.root)).not.toBeInTheDocument(); - - dropdownRef.current?.open(); + act(() => { + dropdownRef.current?.open(); + }); expect(screen.getByTestId(MenuItemDataTids.root)).toBeInTheDocument(); - - dropdownRef.current?.close(); + act(() => { + dropdownRef.current?.close(); + }); expect(screen.queryByTestId(MenuItemDataTids.root)).not.toBeInTheDocument(); }); }); diff --git a/packages/react-ui/components/DropdownMenu/__stories__/DropdownMenu.creevey.stories.tsx b/packages/react-ui/components/DropdownMenu/__stories__/DropdownMenu.creevey.stories.tsx index 2f0f78e0ffb..47002244018 100644 --- a/packages/react-ui/components/DropdownMenu/__stories__/DropdownMenu.creevey.stories.tsx +++ b/packages/react-ui/components/DropdownMenu/__stories__/DropdownMenu.creevey.stories.tsx @@ -13,7 +13,7 @@ import { ReactUIFeatureFlagsContext } from '../../../lib/featureFlagsContext'; export default { title: 'DropdownMenu/Functional tests', decorators: [ - (Story) => ( + (Story: () => JSX.Element) => (
( + (Story: () => JSX.Element) => (
', () => { expect(renderNoCaption).toThrow(); }); - it('Contains after clicking on caption', () => { + it('Contains after clicking on caption', async () => { render( Test , ); expect(screen.queryByTestId(MenuDataTids.root)).not.toBeInTheDocument(); - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); expect(screen.getByTestId(MenuDataTids.root)).toBeInTheDocument(); }); - it("Contains 's after clicking on caption", () => { + it("Contains 's after clicking on caption", async () => { render( Test @@ -49,12 +49,12 @@ describe('', () => { ); expect(screen.queryByTestId(MenuItemDataTids.root)).not.toBeInTheDocument(); - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); expect(screen.getAllByTestId(MenuItemDataTids.root)).toHaveLength(3); }); - it('Click handler on menu item should be called before closing', () => { + it('Click handler on menu item should be called before closing', async () => { const onClick = jest.fn(); render( @@ -63,14 +63,14 @@ describe('', () => { , ); expect(screen.queryByTestId(MenuItemDataTids.root)).not.toBeInTheDocument(); - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); expect(screen.getByTestId(MenuItemDataTids.root)).toBeInTheDocument(); - userEvent.click(screen.getByTestId(MenuItemDataTids.root)); + await userEvent.click(screen.getByTestId(MenuItemDataTids.root)); expect(onClick).toHaveBeenCalled(); }); - it('Fire onOpen and onClose when open and close dropdown', () => { + it('Fire onOpen and onClose when open and close dropdown', async () => { const onOpen = jest.fn(); const onClose = jest.fn(); render( @@ -80,15 +80,15 @@ describe('', () => { ); // open - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); expect(onOpen.mock.calls).toHaveLength(1); // close - userEvent.click(screen.getByTestId(MenuItemDataTids.root)); + await userEvent.click(screen.getByTestId(MenuItemDataTids.root)); expect(onClose.mock.calls).toHaveLength(1); }); - it('Renders header', () => { + it('Renders header', async () => { const testHeader = 'testHeader'; render( Test header
}> @@ -96,11 +96,11 @@ describe('', () => { , ); - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); expect(screen.getByTestId(testHeader)).toBeInTheDocument(); }); - it('Renders footer', () => { + it('Renders footer', async () => { const testFooter = 'testFooter'; render( Test header
}> @@ -108,7 +108,7 @@ describe('', () => { , ); - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); expect(screen.getByTestId(testFooter)).toBeInTheDocument(); }); @@ -121,12 +121,13 @@ describe('', () => { Test , ); - - dropdownMenuRef.current?.open(); + act(() => { + dropdownMenuRef.current?.open(); + }); expect(screen.getByTestId(MenuItemDataTids.root)).toBeInTheDocument(); }); - it('Public method close() works', () => { + it('Public method close() works', async () => { const dropdownMenuRef = React.createRef(); render( @@ -134,20 +135,22 @@ describe('', () => { Test , ); - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); - dropdownMenuRef.current?.close(); + act(() => { + dropdownMenuRef.current?.close(); + }); expect(screen.queryByTestId(MenuItemDataTids.root)).not.toBeInTheDocument(); }); - it('prop `popupMenuId` sets an `id` for root of the popup', () => { + it('prop `popupMenuId` sets an `id` for root of the popup', async () => { const menuId = 'menu'; render( test} popupMenuId={menuId}>

test

, ); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); const menu = screen.getByTestId(PopupDataTids.root); expect(menu).toHaveAttribute('id', menuId); @@ -179,17 +182,17 @@ describe('', () => { ), ); it("doesn't highlight a not selectable MenuItem", async () => { - userEvent.click(screen.getByTestId(captionDatatid)); - userEvent.keyboard('{arrowdown}'); - userEvent.keyboard('{arrowdown}'); + await userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.keyboard('{arrowdown}'); + await userEvent.keyboard('{arrowdown}'); await delay(0); expect(screen.getByTestId('menuItem2')).not.toHaveAttribute('state', 'hover'); expect(screen.getByTestId('menuItem3')).toHaveAttribute('state', 'hover'); }); it("doesn't click on a not selectable MenuItem", async () => { - userEvent.click(screen.getByTestId(captionDatatid)); - userEvent.click(screen.getByTestId('menuItem2')); + await userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId('menuItem2')); await delay(0); expect(screen.getByTestId(MenuDataTids.root)).toBeInTheDocument(); }); diff --git a/packages/react-ui/components/FileUploader/FileUploader.tsx b/packages/react-ui/components/FileUploader/FileUploader.tsx index 591899de741..c5a20f5c515 100644 --- a/packages/react-ui/components/FileUploader/FileUploader.tsx +++ b/packages/react-ui/components/FileUploader/FileUploader.tsx @@ -188,16 +188,16 @@ const _FileUploader = React.forwardRef((pro ); const handleDrop = useCallback( - (event) => { + (event: DragEvent) => { if (disabled) { return; } const { dataTransfer } = event; - const { files } = dataTransfer; - - if (files?.length > 0) { - handleChange(files); + if (dataTransfer) { + if (dataTransfer.files?.length > 0) { + handleChange(dataTransfer.files); + } dataTransfer.clearData(); } }, diff --git a/packages/react-ui/components/FileUploader/__tests__/FileUploader-test.tsx b/packages/react-ui/components/FileUploader/__tests__/FileUploader-test.tsx index 941ce07efce..be2ae51db7a 100644 --- a/packages/react-ui/components/FileUploader/__tests__/FileUploader-test.tsx +++ b/packages/react-ui/components/FileUploader/__tests__/FileUploader-test.tsx @@ -1,4 +1,4 @@ -import React, { RefAttributes } from 'react'; +import React from 'react'; import { act } from 'react-dom/test-utils'; import { fireEvent, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; @@ -30,7 +30,7 @@ const getFilesList = () => { const addFiles = async (files: File[]) => { await act(async () => { - const input = screen.getByTestId(FileUploaderDataTids.root).querySelector('input[type="file"]'); + const input = screen.getByTestId(FileUploaderDataTids.input); if (input !== null) { fireEvent.change(input, { target: { files } }); } @@ -41,7 +41,7 @@ const addFiles = async (files: File[]) => { const removeFile = async () => { await act(async () => { - userEvent.click(screen.getByTestId(FileUploaderFileDataTids.fileIcon)); + await userEvent.click(screen.getByTestId(FileUploaderFileDataTids.fileIcon)); }); }; @@ -106,8 +106,7 @@ describe('FileUploader', () => { }); describe('Handlers', () => { - const renderComp = (props: FileUploaderProps & RefAttributes = {}) => - render(); + const renderComp = (props: FileUploaderProps) => render(); let file: File; const readFile = { @@ -126,7 +125,7 @@ describe('FileUploader', () => { const onFocus = jest.fn(); renderComp({ onFocus }); - userEvent.tab(); + await userEvent.tab(); const input = screen.getByTestId(FileUploaderDataTids.input); expect(input).toHaveFocus(); expect(onFocus).toHaveBeenCalledTimes(1); @@ -136,7 +135,7 @@ describe('FileUploader', () => { const onFocus = jest.fn(); renderComp({ onFocus, disabled: true }); - userEvent.tab(); + await userEvent.tab(); const input = screen.getByTestId(FileUploaderDataTids.input); expect(input).not.toHaveFocus(); @@ -149,7 +148,7 @@ describe('FileUploader', () => { const onBlur = jest.fn(); renderComp({ onBlur }); - userEvent.tab(); + await userEvent.tab(); const input = screen.getByTestId(FileUploaderDataTids.input); expect(input).toHaveFocus(); if (input !== null) { @@ -304,7 +303,7 @@ describe('FileUploader', () => { it('should handle onValueChange after reset', async () => { const onValueChange = jest.fn(); const ref = React.createRef(); - renderComp({ onValueChange, ref }); + render(); await addFiles([file]); diff --git a/packages/react-ui/components/FxInput/__stories__/FxInput.stories.tsx b/packages/react-ui/components/FxInput/__stories__/FxInput.stories.tsx index 617ce2bfd93..23d8d10f9ae 100644 --- a/packages/react-ui/components/FxInput/__stories__/FxInput.stories.tsx +++ b/packages/react-ui/components/FxInput/__stories__/FxInput.stories.tsx @@ -116,7 +116,7 @@ interface TestWrapperProps { width?: number | string; ruler?: boolean; } -class TestWrapper extends React.Component { +class TestWrapper extends React.Component> { public render() { const { width, ruler, children } = this.props; const style: React.CSSProperties = { diff --git a/packages/react-ui/components/FxInput/__tests__/FxInput-test.tsx b/packages/react-ui/components/FxInput/__tests__/FxInput-test.tsx index ece8e24df1b..be519742f79 100644 --- a/packages/react-ui/components/FxInput/__tests__/FxInput-test.tsx +++ b/packages/react-ui/components/FxInput/__tests__/FxInput-test.tsx @@ -25,7 +25,7 @@ describe('FxInput', () => { expect(document.body).toHaveFocus(); }); - it.each(['', undefined])('should clear the value when %s passed', (testValue) => { + it.each(['', undefined])('should clear the value when %s passed', async (testValue) => { const Comp = () => { const [value, setValue] = useState('12345'); @@ -42,10 +42,10 @@ describe('FxInput', () => { const input = screen.getByRole('textbox'); expect(input).toHaveValue('12345'); - userEvent.click(screen.getByRole('button', { name: 'Clear' })); + await userEvent.click(screen.getByRole('button', { name: 'Clear' })); expect(input).toHaveValue(''); - userEvent.type(input, '123'); + await userEvent.type(input, '123'); expect(input).toHaveValue('123'); }); diff --git a/packages/react-ui/components/Gapped/__stories__/Gapped.stories.tsx b/packages/react-ui/components/Gapped/__stories__/Gapped.stories.tsx index 77f759d5641..deb92c0886f 100644 --- a/packages/react-ui/components/Gapped/__stories__/Gapped.stories.tsx +++ b/packages/react-ui/components/Gapped/__stories__/Gapped.stories.tsx @@ -7,7 +7,7 @@ import { Button } from '../../Button'; export default { title: 'Gapped', decorators: [ - (Story) => ( + (Story: () => JSX.Element) => (
diff --git a/packages/react-ui/components/GlobalLoader/__tests__/GlobalLoader-test.tsx b/packages/react-ui/components/GlobalLoader/__tests__/GlobalLoader-test.tsx index da571ed20e9..102ec41c0f8 100644 --- a/packages/react-ui/components/GlobalLoader/__tests__/GlobalLoader-test.tsx +++ b/packages/react-ui/components/GlobalLoader/__tests__/GlobalLoader-test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { act, render, screen } from '@testing-library/react'; import { GlobalLoader, GlobalLoaderDataTids } from '../GlobalLoader'; import { delay } from '../../../lib/utils'; @@ -175,21 +175,29 @@ describe('Global Loader', () => { }); it('should set error', async () => { - GlobalLoader.start(); + act(() => { + GlobalLoader.start(); + }); await delay(DELAY_BEFORE_GLOBAL_LOADER_SHOW); expect(screen.getByTestId(GlobalLoaderDataTids.root)).toBeInTheDocument(); - GlobalLoader.reject(); + act(() => { + GlobalLoader.reject(); + }); expect(screen.getByTestId(GlobalLoaderDataTids.root)).toBeInTheDocument(); expect(screen.getByTestId(GlobalLoaderDataTids.root)).toHaveAttribute('data-status', 'error'); }); it('should set success', async () => { - GlobalLoader.start(); + act(() => { + GlobalLoader.start(); + }); await delay(DELAY_BEFORE_GLOBAL_LOADER_SHOW); expect(screen.getByTestId(GlobalLoaderDataTids.root)).toBeInTheDocument(); - GlobalLoader.done(); + act(() => { + GlobalLoader.done(); + }); expect(screen.getByTestId(GlobalLoaderDataTids.root)).toHaveAttribute('data-status', 'success'); await delay(DELAY_BEFORE_GLOBAL_LOADER_HIDE); @@ -197,10 +205,16 @@ describe('Global Loader', () => { }); it('should start after success animation', async () => { - GlobalLoader.start(); + act(() => { + GlobalLoader.start(); + }); await delay(DELAY_BEFORE_GLOBAL_LOADER_SHOW); - GlobalLoader.done(); - GlobalLoader.start(); + act(() => { + GlobalLoader.done(); + }); + act(() => { + GlobalLoader.start(); + }); await delay(DELAY_BEFORE_GLOBAL_LOADER_HIDE); expect(screen.queryByTestId(GlobalLoaderDataTids.root)).not.toBeInTheDocument(); diff --git a/packages/react-ui/components/Hint/__stories__/Hint.stories.tsx b/packages/react-ui/components/Hint/__stories__/Hint.stories.tsx index 6d9acbec744..424b129e943 100644 --- a/packages/react-ui/components/Hint/__stories__/Hint.stories.tsx +++ b/packages/react-ui/components/Hint/__stories__/Hint.stories.tsx @@ -15,7 +15,7 @@ import { ReactUIFeatureFlagsContext } from '../../../lib/featureFlagsContext'; export default { title: 'Hint', decorators: [ - (Story) => ( + (Story: () => JSX.Element) => (
diff --git a/packages/react-ui/components/Hint/__tests__/Hint-test.tsx b/packages/react-ui/components/Hint/__tests__/Hint-test.tsx index 64f4edc150f..34dedc5522d 100644 --- a/packages/react-ui/components/Hint/__tests__/Hint-test.tsx +++ b/packages/react-ui/components/Hint/__tests__/Hint-test.tsx @@ -29,7 +29,7 @@ describe('Hint', () => { expect(hintContent).not.toBeInTheDocument(); }); - it('should open hint manually', () => { + it('should open hint manually', async () => { const hintText = 'world'; const Component = () => { const [isOpen, setIsOpen] = useState(false); @@ -50,13 +50,13 @@ describe('Hint', () => { expect(hintContent).not.toBeInTheDocument(); const openButton = screen.getByRole('button'); - userEvent.click(openButton); + await userEvent.click(openButton); const hintContentUpdated = screen.getByText(hintText); expect(hintContentUpdated).toBeInTheDocument(); }); - it('handels onMouseEnter event', () => { + it('handels onMouseEnter event', async () => { const onMouseEnter = jest.fn(); const hintChildrenText = 'Hello'; render( @@ -65,12 +65,12 @@ describe('Hint', () => { , ); - userEvent.hover(screen.getByText(hintChildrenText)); + await userEvent.hover(screen.getByText(hintChildrenText)); expect(onMouseEnter).toHaveBeenCalledTimes(1); }); - it('handels onMouseLeave event', () => { + it('handels onMouseLeave event', async () => { const onMouseLeave = jest.fn(); const hintChildrenText = 'Hello'; render( @@ -78,13 +78,12 @@ describe('Hint', () => { {hintChildrenText} , ); - userEvent.unhover(screen.getByText(hintChildrenText)); + await userEvent.unhover(screen.getByText(hintChildrenText)); expect(onMouseLeave).toHaveBeenCalledTimes(1); }); - it('clears timer after unmount', () => { - jest.useFakeTimers(); + it('clears timer after unmount', async () => { jest.spyOn(window, 'setTimeout'); jest.spyOn(window, 'clearTimeout'); @@ -99,7 +98,7 @@ describe('Hint', () => { // @ts-expect-error: Use of private property. expect(hintRef.current.timer).toBeUndefined(); - userEvent.hover(screen.getByText('Anchor')); + await userEvent.hover(screen.getByText('Anchor')); // @ts-expect-error: Use of private property. const { timer } = hintRef.current; diff --git a/packages/react-ui/components/Input/Input.tsx b/packages/react-ui/components/Input/Input.tsx index 92ac7591e74..afc9f43a5b4 100644 --- a/packages/react-ui/components/Input/Input.tsx +++ b/packages/react-ui/components/Input/Input.tsx @@ -302,7 +302,7 @@ export class Input extends React.Component { {(theme) => { this.theme = theme; return ( - + {this.renderMain} ); diff --git a/packages/react-ui/components/Input/InputLayout/InputLayoutAsideIcon.tsx b/packages/react-ui/components/Input/InputLayout/InputLayoutAsideIcon.tsx index fe455e6631d..59c650466bf 100644 --- a/packages/react-ui/components/Input/InputLayout/InputLayoutAsideIcon.tsx +++ b/packages/react-ui/components/Input/InputLayout/InputLayoutAsideIcon.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { ReactElement } from 'react'; import { isElement } from 'react-is'; import { isKonturIcon } from '../../../lib/utils'; @@ -30,8 +30,8 @@ export const InputLayoutAsideIcon: React.FunctionComponent - {_icon} - - ) - ); + return _icon ? ( + + {_icon} + + ) : null; }; diff --git a/packages/react-ui/components/Input/InputLayout/InputLayoutAsideText.tsx b/packages/react-ui/components/Input/InputLayout/InputLayoutAsideText.tsx index b91b20db0af..14cefa87a5a 100644 --- a/packages/react-ui/components/Input/InputLayout/InputLayoutAsideText.tsx +++ b/packages/react-ui/components/Input/InputLayout/InputLayoutAsideText.tsx @@ -17,11 +17,9 @@ export const InputLayoutAsideText: React.FunctionComponent - {text} - - ) - ); + return text ? ( + + {text} + + ) : null; }; diff --git a/packages/react-ui/components/Input/__tests__/Input-test.tsx b/packages/react-ui/components/Input/__tests__/Input-test.tsx index 6a9c4275af0..1d5132507e7 100644 --- a/packages/react-ui/components/Input/__tests__/Input-test.tsx +++ b/packages/react-ui/components/Input/__tests__/Input-test.tsx @@ -41,15 +41,15 @@ describe('', () => { }); it('renders leftIcon', () => { - const leftIcon = ; + const leftIcon = ; render(); - expect(document.querySelector('.my-testy-icon')).toBeInTheDocument(); + expect(screen.getByTestId('my-testy-icon')).toBeInTheDocument(); }); it('renders rightIcon', () => { - const rightIcon = ; + const rightIcon = ; render(); - expect(document.querySelector('.my-testy-icon')).toBeInTheDocument(); + expect(screen.getByTestId('my-testy-icon')).toBeInTheDocument(); }); it('renders MaskedInput on mask prop', () => { @@ -80,7 +80,7 @@ describe('', () => { }); }); - it('type can be changed from allowed for masking to forbidden for masking', () => { + it('type can be changed from allowed for masking to forbidden for masking', async () => { const updatedType = 'date'; const Component = () => { const [type, setType] = useState('text'); @@ -94,12 +94,12 @@ describe('', () => { }; render(); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(consoleSpy.mock.calls[0][0]).toContain(`Warning: ${maskErrorMessage(updatedType)}`); }); - it(`prints an error if allowed type changed to forbidden when prop "mask" passed`, () => { + it(`prints an error if allowed type changed to forbidden when prop "mask" passed`, async () => { const updatedType = 'number'; const Component = () => { const [type, setType] = useState('text'); @@ -113,7 +113,7 @@ describe('', () => { }; render(); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(consoleSpy.mock.calls[0][0]).toContain(`Warning: ${maskErrorMessage(updatedType)}`); }); @@ -128,9 +128,9 @@ describe('', () => { expect(screen.getByRole('textbox')).toBeDisabled(); }); - it('cant focus element when its disabled', () => { + it('cant focus element when its disabled', async () => { render(); - userEvent.tab(); + await userEvent.tab(); expect(screen.getByRole('textbox')).not.toHaveFocus(); }); @@ -139,10 +139,10 @@ describe('', () => { expect(screen.getByRole('textbox')).toHaveAttribute('id', 'someId'); }); - it('maxLength prop works', () => { + it('maxLength prop works', async () => { render(); const element = screen.getByRole('textbox'); - userEvent.type(element, '123456'); + await userEvent.type(element, '123456'); expect(element).toHaveValue('12345'); }); @@ -156,11 +156,11 @@ describe('', () => { expect(screen.getByRole('textbox')).toHaveAttribute('title', 'someTitle'); }); - it('handels onClick event', () => { + it('handels onClick event', async () => { const onClick = jest.fn(); render(); const element = screen.getByRole('textbox'); - userEvent.click(element); + await userEvent.click(element); expect(onClick).toHaveBeenCalledTimes(1); }); @@ -178,19 +178,19 @@ describe('', () => { expect(onMouseDown).toHaveBeenCalledTimes(1); }); - it('handels onKeyUp event', () => { + it('handels onKeyUp event', async () => { const onKeyUp = jest.fn(); render(); - userEvent.type(screen.getByRole('textbox'), '{enter}'); + await userEvent.type(screen.getByRole('textbox'), '{enter}'); expect(onKeyUp).toHaveBeenCalledTimes(1); }); - it('handels onInput event', () => { + it('handels onInput event', async () => { const onInput = jest.fn(); render(); const element = screen.getByRole('textbox'); - userEvent.type(element, 'A'); + await userEvent.type(element, 'A'); expect(element).toHaveValue('A'); expect(onInput).toHaveBeenCalledTimes(1); }); @@ -202,12 +202,13 @@ describe('', () => { expect(onCopy).toHaveBeenCalledTimes(1); }); - it('handels onPaste event', () => { + it('handels onPaste event', async () => { const onPaste = jest.fn(); render(); const text = 'It handels onPaste event'; const element = screen.getByRole('textbox'); - userEvent.paste(element, text); + await userEvent.click(element); + await userEvent.paste(text); expect(element).toHaveValue(text); expect(onPaste).toHaveBeenCalledTimes(1); }); @@ -242,8 +243,11 @@ describe('', () => { render(); inputRef.current?.selectAll(); + // eslint-disable-next-line testing-library/no-node-access expect(document.activeElement).toBeInstanceOf(HTMLInputElement); + // eslint-disable-next-line testing-library/no-node-access expect((document.activeElement as HTMLInputElement).selectionStart).toBe(0); + // eslint-disable-next-line testing-library/no-node-access expect((document.activeElement as HTMLInputElement).selectionEnd).toBe(value.length); }); }); @@ -258,7 +262,9 @@ describe('', () => { render(); inputRef.current?.selectAll(); + // eslint-disable-next-line testing-library/no-node-access expect((document.activeElement as HTMLInputElement).selectionStart).toBeUndefined(); + // eslint-disable-next-line testing-library/no-node-access expect((document.activeElement as HTMLInputElement).selectionEnd).toBeUndefined(); expect(consoleSpy.mock.calls[0][0]).toContain(`Warning: ${selectionErrorMessage(type)}`); }); @@ -270,8 +276,11 @@ describe('', () => { render(); inputRef.current?.setSelectionRange(3, 5); + // eslint-disable-next-line testing-library/no-node-access expect(document.activeElement).toBeInstanceOf(HTMLInputElement); + // eslint-disable-next-line testing-library/no-node-access expect((document.activeElement as HTMLInputElement).selectionStart).toBe(3); + // eslint-disable-next-line testing-library/no-node-access expect((document.activeElement as HTMLInputElement).selectionEnd).toBe(5); }); }); @@ -282,35 +291,41 @@ describe('', () => { render(); inputRef.current?.setSelectionRange(0, 1); + // eslint-disable-next-line testing-library/no-node-access expect((document.activeElement as HTMLInputElement).selectionStart).toBeUndefined(); + // eslint-disable-next-line testing-library/no-node-access expect((document.activeElement as HTMLInputElement).selectionEnd).toBeUndefined(); expect(consoleSpy.mock.calls[0][0]).toContain(`Warning: ${selectionErrorMessage(type)}`); }); }); selectionAllowedTypes.forEach((type) => { - it(`selectAllOnFocus prop works with type="${type}"`, () => { + it(`selectAllOnFocus prop works with type="${type}"`, async () => { const value = 'Prop works'; render(); - userEvent.tab(); + await userEvent.tab(); + // eslint-disable-next-line testing-library/no-node-access expect((document.activeElement as HTMLInputElement).selectionStart).toBe(0); + // eslint-disable-next-line testing-library/no-node-access expect((document.activeElement as HTMLInputElement).selectionEnd).toBe(value.length); }); }); selectionForbiddenTypes.forEach((type) => { - it(`selectAllOnFocus prop doesn't work with type="${type}"`, () => { + it(`selectAllOnFocus prop doesn't work with type="${type}"`, async () => { render(); - userEvent.tab(); + await userEvent.tab(); + // eslint-disable-next-line testing-library/no-node-access expect((document.activeElement as HTMLInputElement).selectionStart).toBeNull(); + // eslint-disable-next-line testing-library/no-node-access expect((document.activeElement as HTMLInputElement).selectionEnd).toBeNull(); expect(consoleSpy.mock.calls[0][0]).toContain(`Warning: ${selectionErrorMessage(type)}`); }); }); - it('type can be changed from allowed for selection to forbidden for selection', () => { + it('type can be changed from allowed for selection to forbidden for selection', async () => { const value = 'value'; const updatedType = 'date'; const Component = () => { @@ -327,13 +342,17 @@ describe('', () => { fireEvent.focus(screen.getByRole('textbox')); + // eslint-disable-next-line testing-library/no-node-access expect((document.activeElement as HTMLInputElement).selectionStart).toBe(0); + // eslint-disable-next-line testing-library/no-node-access expect((document.activeElement as HTMLInputElement).selectionEnd).toBe(value.length); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); fireEvent.focus(screen.getByRole('textbox')); + // eslint-disable-next-line testing-library/no-node-access expect((document.activeElement as HTMLInputElement).selectionStart).toBeUndefined(); + // eslint-disable-next-line testing-library/no-node-access expect((document.activeElement as HTMLInputElement).selectionEnd).toBeUndefined(); expect(consoleSpy.mock.calls[0][0]).toContain(`Warning: ${selectionErrorMessage(updatedType)}`); }); @@ -348,7 +367,7 @@ describe('', () => { } }); - it('blink method works', () => { + it('blink method works', async () => { const blinkMock = jest.fn(); const refInput = React.createRef(); render(); @@ -356,29 +375,29 @@ describe('', () => { if (refInput.current) { refInput.current.blink = blinkMock; } - userEvent.type(screen.getByRole('textbox'), '{backspace}'); + await userEvent.type(screen.getByRole('textbox'), '{backspace}'); expect(blinkMock).toHaveBeenCalledTimes(1); }); - it('call handleUnexpectedInput', () => { + it('call handleUnexpectedInput', async () => { const unexpectedInputHandlerMock = jest.fn(); render(); const element = screen.getByRole('textbox'); - userEvent.type(element, '{backspace}'); + await userEvent.type(element, '{backspace}'); expect(unexpectedInputHandlerMock).toHaveBeenCalledTimes(1); - userEvent.type(element, '123'); + await userEvent.type(element, '123'); expect(screen.getByRole('textbox')).toHaveValue('123'); - userEvent.type(element, '{backspace}'); + await userEvent.type(element, '{backspace}'); expect(unexpectedInputHandlerMock).toHaveBeenCalledTimes(1); }); - it('should clear the value when an empty string passed', () => { + it('should clear the value when an empty string passed', async () => { const Comp = () => { const [value, setValue] = useState(''); @@ -395,49 +414,49 @@ describe('', () => { const input = screen.getByRole('textbox'); expect(input).toHaveValue(''); - userEvent.type(input, 'abc'); + await userEvent.type(input, 'abc'); expect(input).toHaveValue('abc'); - userEvent.click(screen.getByRole('button', { name: 'Clear' })); + await userEvent.click(screen.getByRole('button', { name: 'Clear' })); expect(input).toHaveValue(''); - userEvent.type(input, 'a'); + await userEvent.type(input, 'a'); expect(input).toHaveValue('a'); }); - it('handels onBlur event', () => { + it('handels onBlur event', async () => { const onBlur = jest.fn(); render(); - userEvent.click(screen.getByRole('textbox')); + await userEvent.click(screen.getByRole('textbox')); screen.getByRole('textbox').blur(); expect(onBlur).toHaveBeenCalledTimes(1); }); - it('handels onFocus event', () => { + it('handels onFocus event', async () => { const onFocus = jest.fn(); render(); - userEvent.click(screen.getByRole('textbox')); + await userEvent.click(screen.getByRole('textbox')); expect(onFocus).toHaveBeenCalledTimes(1); }); - it('handels onKeyDown event', () => { + it('handels onKeyDown event', async () => { const onKeyDown = jest.fn(); render(); - userEvent.type(screen.getByRole('textbox'), '{enter}'); + await userEvent.type(screen.getByRole('textbox'), '{enter}'); expect(onKeyDown).toHaveBeenCalledTimes(1); }); - it('handels onKeyPress event', () => { + it('handels onKeyPress event', async () => { const onKeyPress = jest.fn(); render(); - userEvent.type(screen.getByRole('textbox'), '{enter}'); + await userEvent.type(screen.getByRole('textbox'), '{enter}'); expect(onKeyPress).toHaveBeenCalledTimes(1); }); @@ -480,12 +499,12 @@ describe('', () => { expect(onMouseLeave).toHaveBeenCalledTimes(1); }); - it('maskedInput calls onUnexpectedInput', () => { + it('maskedInput calls onUnexpectedInput', async () => { const unexpectedInputHandlerMock = jest.fn(); render(); - userEvent.click(screen.getByRole('textbox')); - userEvent.keyboard('A'); + await userEvent.click(screen.getByRole('textbox')); + await userEvent.keyboard('A'); expect(unexpectedInputHandlerMock).toHaveBeenCalledTimes(1); }); diff --git a/packages/react-ui/components/Kebab/Kebab.tsx b/packages/react-ui/components/Kebab/Kebab.tsx index 82ac82fa8d4..adf7020c9b2 100644 --- a/packages/react-ui/components/Kebab/Kebab.tsx +++ b/packages/react-ui/components/Kebab/Kebab.tsx @@ -1,4 +1,4 @@ -import React, { AriaAttributes } from 'react'; +import React, { AriaAttributes, ReactElement } from 'react'; import PropTypes from 'prop-types'; import { isElement } from 'react-is'; import { globalObject } from '@skbkontur/global-object'; @@ -255,14 +255,14 @@ export class Kebab extends React.Component { private renderIcon2022() { const { size, icon = } = this.getProps(); - if (isElement(icon) && isKonturIcon(icon)) { + if (isElement(icon) && isKonturIcon(icon as ReactElement)) { const sizes: Record = { small: parseInt(this.theme.kebabIconSizeSmall), medium: parseInt(this.theme.kebabIconSizeMedium), large: parseInt(this.theme.kebabIconSizeLarge), }; - return React.cloneElement(icon, { + return React.cloneElement(icon as ReactElement, { size: icon.props.size ?? sizes[size], color: icon.props.color ?? this.theme.kebabIconColor, }); diff --git a/packages/react-ui/components/Kebab/__stories__/Kebab.creevey.stories.tsx b/packages/react-ui/components/Kebab/__stories__/Kebab.creevey.stories.tsx index 7674542e703..06ce47316df 100644 --- a/packages/react-ui/components/Kebab/__stories__/Kebab.creevey.stories.tsx +++ b/packages/react-ui/components/Kebab/__stories__/Kebab.creevey.stories.tsx @@ -11,7 +11,7 @@ import { Kebab } from '../Kebab'; export default { title: 'Kebab/Functional tests', decorators: [ - (Story) => ( + (Story: () => JSX.Element) => (
( + (Story: () => JSX.Element) => (
{ - it('prop `popupMenuId` sets an `id` for root of the popup', () => { + it('prop `popupMenuId` sets an `id` for root of the popup', async () => { const menuId = 'menu'; render(

test

, ); - userEvent.click(screen.getByTestId(KebabDataTids.caption)); + await userEvent.click(screen.getByTestId(KebabDataTids.caption)); const menu = screen.getByTestId(PopupDataTids.root); expect(menu).toHaveAttribute('id', menuId); }); - it('should focus by pressing tab', () => { + it('should focus by pressing tab', async () => { render(); - userEvent.tab(); + await userEvent.tab(); const kebab = screen.getByTestId(KebabDataTids.caption); expect(kebab).toHaveFocus(); }); - it('should handle blur by pressing tab', () => { + it('should handle blur by pressing tab', async () => { render(); - userEvent.tab(); + await userEvent.tab(); const kebab = screen.getByTestId(KebabDataTids.caption); expect(kebab).toHaveFocus(); - userEvent.tab(); + await userEvent.tab(); expect(kebab).not.toHaveFocus(); }); @@ -61,7 +61,7 @@ describe('Kebab', () => { expect(screen.getByRole('button')).toBeInTheDocument(); }); - it('should connect dropdown with button through aria-controls', () => { + it('should connect dropdown with button through aria-controls', async () => { render( test @@ -69,7 +69,7 @@ describe('Kebab', () => { ); const button = screen.getByRole('button'); - userEvent.click(button); + await userEvent.click(button); expect(button).toHaveAttribute('aria-controls', expect.stringContaining(PopupIds.root)); expect(screen.getByTestId(PopupDataTids.root)).toHaveAttribute('id', expect.stringContaining(PopupIds.root)); diff --git a/packages/react-ui/components/Link/__tests__/Link-test.tsx b/packages/react-ui/components/Link/__tests__/Link-test.tsx index 7fa5e457993..b6a5b5e7b9d 100644 --- a/packages/react-ui/components/Link/__tests__/Link-test.tsx +++ b/packages/react-ui/components/Link/__tests__/Link-test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { LinkProps } from '..'; @@ -8,31 +8,31 @@ import { Link, LinkDataTids } from '../Link'; const renderRTL = (props?: LinkProps) => render(); describe('Link', () => { - it('calls `onClick` when link clicked', () => { + it('calls `onClick` when link clicked', async () => { const onClick = jest.fn(); renderRTL({ onClick }); - userEvent.click(screen.getByTestId(LinkDataTids.root)); + await userEvent.click(screen.getByTestId(LinkDataTids.root)); expect(onClick).toHaveBeenCalled(); }); describe('disabled link', () => { - it('does not call `onClick` when link clicked', () => { + it('does not call `onClick` when link clicked', async () => { const onClick = jest.fn(); renderRTL({ onClick, disabled: true }); const linkElement = screen.getByTestId(LinkDataTids.root); - userEvent.click(linkElement, {}, { skipPointerEventsCheck: true }); + fireEvent.click(linkElement); expect(onClick).toHaveBeenCalledTimes(0); }); - it('does not call `onClick` when Enter pressed', () => { + it('does not call `onClick` when Enter pressed', async () => { const onClick = jest.fn(); renderRTL({ onClick, disabled: true }); - userEvent.type(screen.getByTestId(LinkDataTids.root), '{enter}'); + fireEvent.keyDown(screen.getByTestId(LinkDataTids.root), { key: 'Enter', code: 'Enter' }); expect(onClick).toHaveBeenCalledTimes(0); }); }); @@ -81,7 +81,7 @@ describe('Link', () => { const ariaLabel = 'aria-label'; render(); - expect(screen.getByRole('link')).toHaveAttribute('aria-label', ariaLabel); + expect(screen.getByTestId(LinkDataTids.root)).toHaveAttribute('aria-label', ariaLabel); }); }); }); diff --git a/packages/react-ui/components/Loader/__stories__/Loader.stories.tsx b/packages/react-ui/components/Loader/__stories__/Loader.stories.tsx index 80b24b63be4..485d59c8b17 100644 --- a/packages/react-ui/components/Loader/__stories__/Loader.stories.tsx +++ b/packages/react-ui/components/Loader/__stories__/Loader.stories.tsx @@ -28,7 +28,7 @@ interface ContentComponentProps { additionalStyle?: AnyObject; loaderProps?: Partial; } -class ContentComponent extends React.Component { +class ContentComponent extends React.Component> { public render() { const { additionalStyle, loaderProps, children } = this.props; return ( diff --git a/packages/react-ui/components/MaskedInput/__tests__/MaskedInput-test.tsx b/packages/react-ui/components/MaskedInput/__tests__/MaskedInput-test.tsx index 0df0d521b86..89991078985 100644 --- a/packages/react-ui/components/MaskedInput/__tests__/MaskedInput-test.tsx +++ b/packages/react-ui/components/MaskedInput/__tests__/MaskedInput-test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { fireEvent, render, screen } from '@testing-library/react'; +import { act, fireEvent, render, screen } from '@testing-library/react'; import { MaskedInput, MaskedInputProps } from '../MaskedInput'; @@ -88,7 +88,9 @@ describe('MaskedInput', () => { render(); const input = screen.getByRole('textbox'); - input.focus(); + act(() => { + input.focus(); + }); expect(input).toHaveValue('+7 ('); }); @@ -101,8 +103,10 @@ describe('MaskedInput', () => { render(); const input = screen.getByRole('textbox'); - input.focus(); - input.blur(); + act(() => { + input.focus(); + input.blur(); + }); expect(input).toHaveValue(expectedValue); }); @@ -112,7 +116,9 @@ describe('MaskedInput', () => { render(); const input = screen.getByRole('textbox'); - input.focus(); + act(() => { + input.focus(); + }); expect(valueChangeEvent).not.toHaveBeenCalled(); }); diff --git a/packages/react-ui/components/MenuItem/MenuItem.tsx b/packages/react-ui/components/MenuItem/MenuItem.tsx index 3b8047ac3d8..7aafd23c27d 100644 --- a/packages/react-ui/components/MenuItem/MenuItem.tsx +++ b/packages/react-ui/components/MenuItem/MenuItem.tsx @@ -168,7 +168,7 @@ export class MenuItem extends React.Component { this.theme = theme; return ( - {this.renderMain} + {this.renderMain(this.props)} ); }} @@ -360,7 +360,7 @@ export class MenuItem extends React.Component { ref={this.contentRef} data-tid={MenuItemDataTids.content} > - {content} + {typeof content === 'function' ? content() : content} {this.props.comment && (
{ }); it('calls children function', () => { - render({(state) => state}); + render({(state) => state?.toString()}); expect(screen.getByTestId(MenuItemDataTids.root)).toHaveTextContent('hover'); }); @@ -100,7 +100,7 @@ describe('MenuItem', () => { }); describe('onMouseEnter', () => { - it('calls once', () => { + it('calls once', async () => { const onMouseEnter = jest.fn(); render( @@ -108,20 +108,20 @@ describe('MenuItem', () => { , ); - userEvent.hover(screen.getByRole('button')); - userEvent.hover(screen.getByText('MenuItem')); - userEvent.hover(screen.getByRole('button')); + await userEvent.hover(screen.getByRole('button')); + await userEvent.hover(screen.getByText('MenuItem')); + await userEvent.hover(screen.getByRole('button')); expect(onMouseEnter).toHaveBeenCalledTimes(1); }); - it('calls again after onMouseLeave', () => { + it('calls again after onMouseLeave', async () => { const onMouseEnter = jest.fn(); render(MenuItem); - userEvent.hover(screen.getByRole('button')); - userEvent.unhover(screen.getByRole('button')); - userEvent.hover(screen.getByRole('button')); + await userEvent.hover(screen.getByRole('button')); + await userEvent.unhover(screen.getByRole('button')); + await userEvent.hover(screen.getByRole('button')); expect(onMouseEnter.mock.calls).toHaveLength(2); }); diff --git a/packages/react-ui/components/MiniModal/MiniModalHeader.tsx b/packages/react-ui/components/MiniModal/MiniModalHeader.tsx index fc82036322b..55578b20f16 100644 --- a/packages/react-ui/components/MiniModal/MiniModalHeader.tsx +++ b/packages/react-ui/components/MiniModal/MiniModalHeader.tsx @@ -37,7 +37,12 @@ export const MiniModalHeader = forwardRefAndName )} {children && ( -
+
{children}
)} diff --git a/packages/react-ui/components/MiniModal/MiniModalIndent.tsx b/packages/react-ui/components/MiniModal/MiniModalIndent.tsx index a3834d9ce35..688b0c39c97 100644 --- a/packages/react-ui/components/MiniModal/MiniModalIndent.tsx +++ b/packages/react-ui/components/MiniModal/MiniModalIndent.tsx @@ -13,7 +13,7 @@ import { MiniModalDataTids } from './MiniModal'; * * @visibleName MiniModal.Indent */ -export const MiniModalIndent = forwardRefAndName( +export const MiniModalIndent = forwardRefAndName>( 'MiniModalIndent', ({ children, ...rest }, ref) => { const theme = useContext(ThemeContext); diff --git a/packages/react-ui/components/Modal/__stories__/Modal.stories.tsx b/packages/react-ui/components/Modal/__stories__/Modal.stories.tsx index d6a3552ea09..36c1576fbd8 100644 --- a/packages/react-ui/components/Modal/__stories__/Modal.stories.tsx +++ b/packages/react-ui/components/Modal/__stories__/Modal.stories.tsx @@ -347,7 +347,7 @@ interface ModalWithVariableHeightState { opened: boolean; panel: boolean; } -class ModalWithVariableHeight extends React.Component { +class ModalWithVariableHeight extends React.Component { public state: ModalWithVariableHeightState = { opened: false, panel: false, diff --git a/packages/react-ui/components/Modal/__tests__/Modal-test.tsx b/packages/react-ui/components/Modal/__tests__/Modal-test.tsx index 2e127ff925c..28c00609a4f 100644 --- a/packages/react-ui/components/Modal/__tests__/Modal-test.tsx +++ b/packages/react-ui/components/Modal/__tests__/Modal-test.tsx @@ -45,7 +45,7 @@ describe('Modal', () => { ).not.toThrow(); }); - it('Non-sticky header works', () => { + it('Non-sticky header works', async () => { const Component = () => { const [isSticky, setIsSticky] = useState(true); @@ -59,11 +59,11 @@ describe('Modal', () => { render(); expect(screen.getByTestId(StickyDataTids.root)).toBeInTheDocument(); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(screen.queryByTestId(StickyDataTids.root)).not.toBeInTheDocument(); }); - it('Non-sticky footer works', () => { + it('Non-sticky footer works', async () => { const Component = () => { const [isSticky, setIsSticky] = useState(true); @@ -77,11 +77,11 @@ describe('Modal', () => { render(); expect(screen.getByTestId(StickyDataTids.root)).toBeInTheDocument(); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(screen.queryByTestId(StickyDataTids.root)).not.toBeInTheDocument(); }); - it('onClose handler works', () => { + it('onClose handler works', async () => { const onCloseHandler = jest.fn(); render( @@ -89,7 +89,7 @@ describe('Modal', () => { , ); expect(onCloseHandler).not.toHaveBeenCalled(); - userEvent.click(screen.getByTestId(ModalDataTids.close)); + await userEvent.click(screen.getByTestId(ModalDataTids.close)); expect(onCloseHandler).toHaveBeenCalledTimes(1); }); diff --git a/packages/react-ui/components/Paging/__stories__/Paging.stories.tsx b/packages/react-ui/components/Paging/__stories__/Paging.stories.tsx index 423bbd2b01b..79399e38c51 100644 --- a/packages/react-ui/components/Paging/__stories__/Paging.stories.tsx +++ b/packages/react-ui/components/Paging/__stories__/Paging.stories.tsx @@ -135,7 +135,7 @@ class PagingWithCustomComponent extends React.Component ( + (Story: () => JSX.Element) => (
diff --git a/packages/react-ui/components/Paging/__tests__/Paging-test.tsx b/packages/react-ui/components/Paging/__tests__/Paging-test.tsx index 56f245f2e28..2e60c2ab9f0 100644 --- a/packages/react-ui/components/Paging/__tests__/Paging-test.tsx +++ b/packages/react-ui/components/Paging/__tests__/Paging-test.tsx @@ -9,10 +9,10 @@ import { PagingLocaleHelper } from '../locale'; import { Paging, PagingDataTids } from '../Paging'; describe('Paging', () => { - it('should keep focus on body when the component is disabled', () => { + it('should keep focus on body when the component is disabled', async () => { render(); - userEvent.tab(); + await userEvent.tab(); expect(document.body).toHaveFocus(); }); diff --git a/packages/react-ui/components/PasswordInput/PasswordInput.tsx b/packages/react-ui/components/PasswordInput/PasswordInput.tsx index e63e08f8f69..43c58115ce0 100644 --- a/packages/react-ui/components/PasswordInput/PasswordInput.tsx +++ b/packages/react-ui/components/PasswordInput/PasswordInput.tsx @@ -101,7 +101,7 @@ export class PasswordInput extends React.PureComponent - {this.renderMain} + {this.renderMain(this.props)} ); }} diff --git a/packages/react-ui/components/PasswordInput/__tests__/PasswordInput-test.tsx b/packages/react-ui/components/PasswordInput/__tests__/PasswordInput-test.tsx index 0eb8368127f..9ea0d7c3b3f 100644 --- a/packages/react-ui/components/PasswordInput/__tests__/PasswordInput-test.tsx +++ b/packages/react-ui/components/PasswordInput/__tests__/PasswordInput-test.tsx @@ -9,20 +9,20 @@ import { componentsLocales as PasswordInputLocaleEn } from '../locale/locales/en import { componentsLocales as PasswordInputLocaleRu } from '../locale/locales/ru'; describe('PasswordInput', () => { - it('should change icon after clicking on the toggle button', () => { + it('should change icon after clicking on the toggle button', async () => { render(); const toggleButton = screen.getByTestId(PasswordInputDataTids.eyeIcon); const toggleButtonInitialIcon = toggleButton.innerHTML; - userEvent.click(toggleButton); + await userEvent.click(toggleButton); const toggleButtonUpdatedIcon = toggleButton.innerHTML; expect(toggleButtonInitialIcon).not.toBe(toggleButtonUpdatedIcon); }); - it('should change input type after clicking on the toggle button', () => { + it('should change input type after clicking on the toggle button', async () => { const inputValue = 'input'; render(); @@ -33,7 +33,7 @@ describe('PasswordInput', () => { expect(input).toHaveAttribute('type', 'password'); const toggleButton = screen.getByTestId(PasswordInputDataTids.eyeIcon); - userEvent.click(toggleButton); + await userEvent.click(toggleButton); // After clicking on the toggle button input should have type `text` expect(input).toHaveAttribute('type', 'text'); @@ -52,7 +52,7 @@ describe('PasswordInput', () => { expect(component.find(`[data-tid~="PasswordInputCapsLockDetector"]`)).toHaveLength(0); }); - it('should focus on the input after clicking on the toggle button', () => { + it('should focus on the input after clicking on the toggle button', async () => { const inputValue = 'input'; render(); @@ -64,12 +64,12 @@ describe('PasswordInput', () => { // Input should have type `password` at the moment expect(input).not.toHaveFocus(); - userEvent.click(toggleButton); + await userEvent.click(toggleButton); // After clicking on the toggle button input should get focus // Input should have type `text` at the moment expect(input).toHaveFocus(); - userEvent.click(toggleButton); + await userEvent.click(toggleButton); // After re-clicking on the toggle button input should get focus again // Input should have type `password` at the moment expect(input).toHaveFocus(); @@ -98,24 +98,24 @@ describe('PasswordInput', () => { expect(screen.queryByDisplayValue(inputValue)).not.toHaveFocus(); }); - it('handels onKeyPress event', () => { + it('handels onKeyPress event', async () => { const onKeyPress = jest.fn(); const inputValue = 'input'; render(); - userEvent.type(screen.getByDisplayValue(inputValue), '{enter}'); + await userEvent.type(screen.getByDisplayValue(inputValue), '{enter}'); expect(onKeyPress).toHaveBeenCalledTimes(1); }); - it('handels onKeyDown event', () => { + it('handels onKeyDown event', async () => { const onKeyDown = jest.fn(); const inputValue = 'input'; render(); - userEvent.type(screen.getByDisplayValue(inputValue), '{enter}'); + await userEvent.type(screen.getByDisplayValue(inputValue), '{enter}'); expect(onKeyDown).toHaveBeenCalledTimes(1); }); @@ -125,14 +125,14 @@ describe('PasswordInput', () => { expect(screen.queryByTestId(PasswordInputDataTids.eyeIcon)).not.toBeInTheDocument(); }); - it('should hide symbols on click outside', () => { + it('should hide symbols on click outside', async () => { const inputValue = 'input'; render(); - userEvent.click(screen.getByTestId(PasswordInputDataTids.eyeIcon)); + await userEvent.click(screen.getByTestId(PasswordInputDataTids.eyeIcon)); expect(screen.getByDisplayValue(inputValue)).toHaveAttribute('type', 'text'); - userEvent.click(document.body); + await userEvent.click(document.body); expect(screen.getByDisplayValue(inputValue)).toHaveAttribute('type', 'password'); }); @@ -143,27 +143,27 @@ describe('PasswordInput', () => { }); describe('a11y', () => { - it('sets value for aria-label attribute', () => { + it('sets value for aria-label attribute', async () => { const ariaLabel = 'aria-label'; render(); // Clicking on the eye icon to turn input from password to text - userEvent.click(screen.getByTestId(PasswordInputDataTids.eyeIcon)); + await userEvent.click(screen.getByTestId(PasswordInputDataTids.eyeIcon)); expect(screen.getByRole('textbox')).toHaveAttribute('aria-label', ariaLabel); }); - it('eye icon has correct aria-label attribute (ru)', () => { + it('eye icon has correct aria-label attribute (ru)', async () => { render(); expect(screen.getByRole('button')).toHaveAttribute('aria-label', PasswordInputLocaleRu.eyeOpenedAriaLabel); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(screen.getByRole('button')).toHaveAttribute('aria-label', PasswordInputLocaleRu.eyeClosedAriaLabel); }); - it('eye icon has correct aria-label attribute (en)', () => { + it('eye icon has correct aria-label attribute (en)', async () => { render( @@ -172,7 +172,7 @@ describe('PasswordInput', () => { expect(screen.getByRole('button')).toHaveAttribute('aria-label', PasswordInputLocaleEn.eyeOpenedAriaLabel); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(screen.getByRole('button')).toHaveAttribute('aria-label', PasswordInputLocaleEn.eyeClosedAriaLabel); }); @@ -188,7 +188,7 @@ describe('PasswordInput', () => { expect(screen.getByRole('button')).toHaveAttribute('aria-label', customAriaLabel); }); - it('sets custom value for `eyeClosedAriaLabel` locale', () => { + it('sets custom value for `eyeClosedAriaLabel` locale', async () => { const customAriaLabel = 'test'; render( @@ -196,7 +196,7 @@ describe('PasswordInput', () => { , ); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(screen.getByRole('button')).toHaveAttribute('aria-label', customAriaLabel); }); diff --git a/packages/react-ui/components/Radio/Radio.tsx b/packages/react-ui/components/Radio/Radio.tsx index 7201f401ac1..79bee08961e 100644 --- a/packages/react-ui/components/Radio/Radio.tsx +++ b/packages/react-ui/components/Radio/Radio.tsx @@ -145,7 +145,7 @@ export class Radio extends React.Component, RadioState> { {(theme) => { this.theme = theme; return ( - + {this.renderMain} ); diff --git a/packages/react-ui/components/Radio/__tests__/Radio-test.tsx b/packages/react-ui/components/Radio/__tests__/Radio-test.tsx index b063cfb015b..12583de0895 100644 --- a/packages/react-ui/components/Radio/__tests__/Radio-test.tsx +++ b/packages/react-ui/components/Radio/__tests__/Radio-test.tsx @@ -48,18 +48,18 @@ describe('Radio', () => { expect(onFocus).toHaveBeenCalledTimes(1); }); - it('should handle onValueChange event', () => { + it('should handle onValueChange event', async () => { const onValueChange = jest.fn(); const radioRef = React.createRef>(); render(); - userEvent.click(screen.getByRole('radio')); + await userEvent.click(screen.getByRole('radio')); expect(onValueChange).toHaveBeenCalledTimes(1); }); - it('should focus by tab pressing', () => { + it('should focus by tab pressing', async () => { render(); - userEvent.tab(); + await userEvent.tab(); expect(screen.getByRole('radio')).toHaveFocus(); }); @@ -80,7 +80,7 @@ describe('Radio', () => { expect(screen.getByRole('radio')).not.toHaveFocus(); }); - it('should check radio in RadioGroup', () => { + it('should check radio in RadioGroup', async () => { render( @@ -89,7 +89,7 @@ describe('Radio', () => { ); const radios = screen.getAllByRole('radio'); - userEvent.click(radios[0]); + await userEvent.click(radios[0]); expect(screen.getAllByRole('radio')[0]).toBeChecked(); }); }); diff --git a/packages/react-ui/components/RadioGroup/RadioGroup.tsx b/packages/react-ui/components/RadioGroup/RadioGroup.tsx index 7c6107bc7c2..b1cc45f1e54 100644 --- a/packages/react-ui/components/RadioGroup/RadioGroup.tsx +++ b/packages/react-ui/components/RadioGroup/RadioGroup.tsx @@ -275,7 +275,7 @@ function mapItems( function normalizeEntry(entry: T | [T, React.ReactNode]): [T, React.ReactNode] { if (!Array.isArray(entry)) { - return [entry, entry]; + return [entry, entry as unknown as React.ReactNode]; } return entry; } diff --git a/packages/react-ui/components/RadioGroup/__tests__/RadioGroup-test.tsx b/packages/react-ui/components/RadioGroup/__tests__/RadioGroup-test.tsx index 42e97074585..cd1c28f733e 100644 --- a/packages/react-ui/components/RadioGroup/__tests__/RadioGroup-test.tsx +++ b/packages/react-ui/components/RadioGroup/__tests__/RadioGroup-test.tsx @@ -52,20 +52,20 @@ describe('', () => { }); }); - it('checks radio on click', () => { + it('checks radio on click', async () => { renderRadioGroup({ items }); const radios = screen.getAllByTestId(RadioDataTids.root); - userEvent.click(radios[clickedIndex]); + await userEvent.click(radios[clickedIndex]); expect(screen.getAllByRole('radio')[clickedIndex]).toBeChecked(); }); - it('calls onValueChange on radio click', () => { + it('calls onValueChange on radio click', async () => { const onValueChange = jest.fn(); renderRadioGroup({ items, onValueChange }); const radios = screen.getAllByTestId(RadioDataTids.root); - userEvent.click(radios[clickedIndex]); + await userEvent.click(radios[clickedIndex]); expect(onValueChange).toHaveBeenCalled(); const [value] = onValueChange.mock.calls[0]; @@ -122,7 +122,7 @@ describe('', () => { expect(screen.getByTestId('myDupaComponent')).toBeInTheDocument(); }); - it('checks children radio on click', () => { + it('checks children radio on click', async () => { const children = (
Hello @@ -133,11 +133,11 @@ describe('', () => { renderRadioGroup({ children }); const radios = screen.getAllByRole('radio'); - userEvent.click(radios[clickedIndex]); + await userEvent.click(radios[clickedIndex]); expect(screen.getAllByRole('radio')[clickedIndex]).toBeChecked(); }); - it('calls onValueChange on children radio click', () => { + it('calls onValueChange on children radio click', async () => { const children = (
Hello @@ -149,7 +149,7 @@ describe('', () => { renderRadioGroup({ children, onValueChange }); const radios = screen.getAllByRole('radio'); - userEvent.click(radios[clickedIndex]); + await userEvent.click(radios[clickedIndex]); expect(onValueChange).toHaveBeenCalled(); const [value] = onValueChange.mock.calls[0]; @@ -214,12 +214,12 @@ describe('', () => { expect(RadioGroup.Prevent).toBeDefined(); }); - it('works with number values', () => { + it('works with number values', async () => { const items = [1, 2, 3, 4]; renderRadioGroup({ items }); const radios = screen.getAllByRole('radio'); - userEvent.click(radios[clickedIndex]); + await userEvent.click(radios[clickedIndex]); expect(screen.getAllByRole('radio')[clickedIndex]).toBeChecked(); }); @@ -237,7 +237,7 @@ describe('', () => { expect(onBlur).toHaveBeenCalledTimes(1); }); - it('should call `onBlur` after click outside of radio group', () => { + it('should call `onBlur` after click outside of radio group', async () => { const onBlur = jest.fn(); const onRadioBlur = jest.fn(); @@ -249,7 +249,7 @@ describe('', () => { ); const radioOne = screen.getAllByRole('radio')[0]; const radioTwo = screen.getAllByRole('radio')[1]; - userEvent.click(radioOne); + await userEvent.click(radioOne); fireEvent.blur(radioOne); fireEvent.blur(radioTwo); diff --git a/packages/react-ui/components/ScrollContainer/__stories__/ScrollContainer.stories.tsx b/packages/react-ui/components/ScrollContainer/__stories__/ScrollContainer.stories.tsx index 13f3acc5de3..2befba5f1ac 100644 --- a/packages/react-ui/components/ScrollContainer/__stories__/ScrollContainer.stories.tsx +++ b/packages/react-ui/components/ScrollContainer/__stories__/ScrollContainer.stories.tsx @@ -27,14 +27,16 @@ const wrapperStyle = { border: '1px solid #000', }; -const DynamicContent: React.FC<{ - state: ScrollContainerScrollStateY | ScrollContainerScrollStateX; - scroll: (percentage: number) => void; - add: () => void; - remove: () => void; - onChangeScrollYState?: (x: ScrollContainerScrollStateY) => void; - onChangeScrollXState?: (x: ScrollContainerScrollStateX) => void; -}> = ({ children, state, scroll, add, remove, onChangeScrollXState, onChangeScrollYState }) => { +const DynamicContent: React.FC< + React.PropsWithChildren<{ + state: ScrollContainerScrollStateY | ScrollContainerScrollStateX; + scroll: (percentage: number) => void; + add: () => void; + remove: () => void; + onChangeScrollYState?: (x: ScrollContainerScrollStateY) => void; + onChangeScrollXState?: (x: ScrollContainerScrollStateX) => void; + }> +> = ({ children, state, scroll, add, remove, onChangeScrollXState, onChangeScrollYState }) => { return (
diff --git a/packages/react-ui/components/Select/Select.tsx b/packages/react-ui/components/Select/Select.tsx index 07773ef77ec..1c464135225 100644 --- a/packages/react-ui/components/Select/Select.tsx +++ b/packages/react-ui/components/Select/Select.tsx @@ -722,7 +722,7 @@ export class Select extends React.Component { +const mobileDecorator = (Story: () => JSX.Element) => { return (
( + (Story: () => JSX.Element) => (
JSX.Element]; export const MobileWithTitle: Story = () => ( JSX.Element]; export const MobileWithoutTitleAndSearch: Story = () => ( ); - userEvent.click(screen.getByTestId(ButtonDataTids.root)); + await userEvent.click(screen.getByTestId(ButtonDataTids.root)); expect(onFocus).toHaveBeenCalledTimes(1); }); - it('should execute `onBlur` with default button', () => { + it('should execute `onBlur` with default button', async () => { const onBlur = jest.fn(); render( {second}), - third, - +fourth, - Select.SEP, - fifth, - {sixth}, - [6, seventh], - [7, eighth, 777], - ninth, - ]} - search - disablePortal - onValueChange={console.log} - />, - ); - - // None of the items should be presented when `Select` is closed. - expect(screen.queryByRole('button', { name: first })).not.toBeInTheDocument(); - expect(screen.queryByText(second)).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: third })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: fourth })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: fifth })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: sixth })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: seventh })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: eighth })).not.toBeInTheDocument(); - expect(screen.queryByText(eighth)).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: ninth })).not.toBeInTheDocument(); - - const button = screen.getByRole('button', { name: SelectLocaleHelper.get(defaultLangCode).placeholder as string }); - await userEvent.click(button); - - // All items should be presented when `Select` is opened. - expect(screen.getByRole('button', { name: first })).toBeInTheDocument(); - expect(screen.getByText(second)).toBeInTheDocument(); - expect(screen.getByRole('button', { name: third })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: fourth })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: fifth })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: sixth })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: seventh })).toBeInTheDocument(); - expect(screen.getByText(eighth)).toBeInTheDocument(); - expect(screen.getByRole('button', { name: ninth })).toBeInTheDocument(); - - const input = screen.getByRole('textbox'); - - await userEvent.type(input, 'e'); - // After entering 'e' only `first`, `second`, `sixth`, `eighth` and `ninth` items should be presented. - expect(screen.getByRole('button', { name: first })).toBeInTheDocument(); - expect(screen.getByText(second)).toBeInTheDocument(); - expect(screen.getByRole('button', { name: sixth })).toBeInTheDocument(); - expect(screen.getByText(eighth)).toBeInTheDocument(); - expect(screen.getByRole('button', { name: ninth })).toBeInTheDocument(); - // All other items should not be presented - expect(screen.queryByRole('button', { name: third })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: fourth })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: fifth })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: seventh })).not.toBeInTheDocument(); - - await userEvent.type(input, 'v'); - // After entering 'ev' only `seventh` item should be presented. - expect(screen.getByText(eighth)).toBeInTheDocument(); - // All other items should not be presented. - expect(screen.queryByRole('button', { name: first })).not.toBeInTheDocument(); - expect(screen.queryByText(second)).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: third })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: fourth })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: fifth })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: sixth })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: seventh })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: ninth })).not.toBeInTheDocument(); - - await userEvent.clear(input); - // After clearing the input all items should be presented again. - expect(screen.getByRole('button', { name: first })).toBeInTheDocument(); - expect(screen.getByText(second)).toBeInTheDocument(); - expect(screen.getByRole('button', { name: third })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: fourth })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: fifth })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: sixth })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: seventh })).toBeInTheDocument(); - expect(screen.getByText(eighth)).toBeInTheDocument(); - expect(screen.getByRole('button', { name: ninth })).toBeInTheDocument(); - - await userEvent.type(input, 's'); - // After entering 's' only `second` and `seventh` items should be presented. - expect(screen.getByText(second)).toBeInTheDocument(); - expect(screen.getByRole('button', { name: seventh })).toBeInTheDocument(); - expect(screen.getByText(eighth)).toBeInTheDocument(); - expect(screen.getByRole('button', { name: ninth })).toBeInTheDocument(); - // All other items should not be presented. - expect(screen.queryByRole('button', { name: first })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: third })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: fourth })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: fifth })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: sixth })).not.toBeInTheDocument(); - await userEvent.clear(input); - - await userEvent.type(input, '3'); - // After entering '3' only `fourth` item should be presented. - expect(screen.getByRole('button', { name: fourth })).toBeInTheDocument(); - // All other items should not be presented. - expect(screen.queryByRole('button', { name: first })).not.toBeInTheDocument(); - expect(screen.queryByText(second)).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: third })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: fifth })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: sixth })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: seventh })).not.toBeInTheDocument(); - expect(screen.queryByText(eighth)).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: ninth })).not.toBeInTheDocument(); - }); - - it('should clear the value when null passed', () => { + it('should clear the value when null passed', async () => { const Comp = () => { const items = ['One']; @@ -227,7 +115,7 @@ describe('Select', () => { const input = screen.getByText('One'); expect(input).toHaveTextContent(/^One$/); - userEvent.click(screen.getByRole('button', { name: 'Clear' })); + await userEvent.click(screen.getByRole('button', { name: 'Clear' })); const placeholderRegExp = new RegExp(`^${SelectLocaleHelper.get(defaultLangCode).placeholder}$`); expect(input).toHaveTextContent(placeholderRegExp); }); @@ -241,26 +129,26 @@ describe('Select', () => { }); describe('a11y', () => { - it('should change value of aria-expanded when opening and closing', () => { + it('should change value of aria-expanded when opening and closing', async () => { render(); const button = screen.getByRole('button'); expect(button).toHaveAttribute('aria-controls', expect.stringContaining(SelectIds.menu)); - userEvent.click(button); + await userEvent.click(button); expect(screen.getByTestId(SelectDataTids.menu)).toHaveAttribute('id', expect.stringContaining(SelectIds.menu)); }); @@ -382,37 +270,52 @@ describe('Select', () => { }); it('should open menu by method', () => { - selectRef.current?.open(); + act(() => { + selectRef.current?.open(); + }); expect(screen.getByTestId(MenuDataTids.root)).toBeInTheDocument(); }); it('should handel onOpen event when open() method has been called', () => { - selectRef.current?.open(); + act(() => { + selectRef.current?.open(); + }); expect(onOpen).toHaveBeenCalled(); }); it('should close menu by method', () => { - selectRef.current?.open(); + act(() => { + selectRef.current?.open(); + }); expect(screen.getByTestId(MenuDataTids.root)).toBeInTheDocument(); - - selectRef.current?.close(); + act(() => { + selectRef.current?.close(); + }); expect(screen.queryByTestId(MenuDataTids.root)).not.toBeInTheDocument(); }); it('should handel onClose event when close() method has been called', () => { - selectRef.current?.open(); - selectRef.current?.close(); + act(() => { + selectRef.current?.open(); + }); + act(() => { + selectRef.current?.close(); + }); expect(onClose).toHaveBeenCalled(); }); it('should not call onClose event when menu wasn`t open', () => { - selectRef.current?.close(); + act(() => { + selectRef.current?.close(); + }); expect(onClose).not.toHaveBeenCalled(); }); it('should focus by method', () => { - selectRef.current?.focus(); + act(() => { + selectRef.current?.focus(); + }); expect(screen.getByRole('button')).toHaveFocus(); }); }); @@ -429,48 +332,180 @@ describe('Select', () => { render(); }); - it('should choose item when pressing enter key', () => { - userEvent.click(screen.getByRole('button')); + it('should choose item when pressing enter key', async () => { + await userEvent.click(screen.getByRole('button')); expect(screen.getByTestId(MenuDataTids.root)).toBeInTheDocument(); - userEvent.keyboard('{arrowdown}'); - userEvent.keyboard('{arrowdown}'); + await userEvent.keyboard('{arrowdown}'); + await userEvent.keyboard('{arrowdown}'); - userEvent.keyboard('{enter}'); + await userEvent.keyboard('{enter}'); expect(screen.queryByTestId(MenuDataTids.root)).not.toBeInTheDocument(); expect(screen.getByRole('button')).toHaveTextContent(testItems[1]); }); - it('should move highligted item when pressing arrow down key', () => { - userEvent.click(screen.getByRole('button')); + it('should move highligted item when pressing arrow down key', async () => { + await userEvent.click(screen.getByRole('button')); expect(screen.getByTestId(MenuDataTids.root)).toBeInTheDocument(); const menuItems = screen.getAllByTestId(MenuItemDataTids.root); expect(menuItems.find((element) => element.hasAttribute('state'))).toBeFalsy(); - userEvent.keyboard('{arrowdown}'); + await userEvent.keyboard('{arrowdown}'); expect( menuItems.find((element) => element.hasAttribute('state') && element.getAttribute('state') === 'hover'), ).toHaveTextContent(testItems[0]); - userEvent.keyboard('{arrowdown}'); + await userEvent.keyboard('{arrowdown}'); expect( menuItems.find((element) => element.hasAttribute('state') && element.getAttribute('state') === 'hover'), ).toHaveTextContent(testItems[1]); }); - it('should move highligted item when pressing arrow up key', () => { - userEvent.click(screen.getByRole('button')); + it('should move highligted item when pressing arrow up key', async () => { + await userEvent.click(screen.getByRole('button')); expect(screen.getByTestId(MenuDataTids.root)).toBeInTheDocument(); const menuItems = screen.getAllByTestId(MenuItemDataTids.root); expect(menuItems.find((element) => element.hasAttribute('state'))).toBeFalsy(); - userEvent.keyboard('{arrowup}'); + await userEvent.keyboard('{arrowup}'); expect( menuItems.find((element) => element.hasAttribute('state') && element.getAttribute('state') === 'hover'), ).toHaveTextContent(testItems[testItems.length - 1]); }); }); + describe('with item of any type', () => { + beforeEach(() => { + render( + , - )} -
-); -HintsWithoutWrapperAroundInlineBlockWith50Width.storyName = 'Hints without wrapper around inline-block with 50% width'; -HintsWithoutWrapperAroundInlineBlockWith50Width.parameters = { creevey: { delay: 500 } }; - -const HandleClickHint = () => { - const [manual, setManual] = React.useState(false); - - const onClick = () => setManual(true); - - return ( -
- -
- Hover me and click -
-
-
- ); -}; - -export const SetManualAndOpenedPropOnClick: Story = () => ; - -SetManualAndOpenedPropOnClick.parameters = { - creevey: { - tests: { - async 'click on hint'() { - await this.browser - .actions() - .click(this.browser.findElement({ css: '#main' })) - .perform(); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('click on hint'); - }, - }, - }, -}; - -export const WithSVGIcon: Story = () => { - return ( - - - - - - ); -}; - -WithSVGIcon.parameters = { - creevey: { - skip: { - 'internal logic being tested and not something UI related': { - in: [ - 'chromeDark', - 'chrome8px', - 'firefox8px', - 'firefox', - 'firefoxFlat8px', - 'firefoxDark', - 'ie118px', - 'ie11', - 'ie11Dark', - ], - }, - }, - tests: { - async idle() { - await this.expect(await this.takeScreenshot()).to.matchImage('idle'); - }, - async hover() { - await this.browser - .actions() - .move({ - origin: this.browser.findElement({ css: '[data-tid="icon"]' }), - }) - .perform(); - await delay(1000); - - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open'); - }, - }, - }, -}; - -@rootNode -class CustomClassComponent extends React.Component { - private setRootNode!: TSetRootNode; - - render() { - return
Ich Liebe dich
; - } -} -export const WithClassChildren = () => ( - - - - - -); -WithClassChildren.storyName = 'with class children'; - -export const KebabHintRemovePinFeatureFlag = () => ( - - - Ich Liebe dich - - -); -KebabHintRemovePinFeatureFlag.storyName = 'with kebabHintRemovePin feature flag'; -KebabHintRemovePinFeatureFlag.parameters = { - creevey: { - skip: { in: /^(?!\b.*2022.*\b)/ }, - }, -}; - -export const HintNearScreenEdge = () => ( - <> -
-
- - - -
Hey there!
} pos="bottom center" trigger="opened"> - -
-
- -
- - - -
Hey there!
} pos="bottom center" trigger="opened"> - -
-
- -
- - - -
Hey there!
} pos="bottom center" trigger="opened"> - -
-
- -
- - - -
Hey there!
} pos="bottom center" trigger="opened"> - -
-
- -
- - - -
Hey there!
} pos="bottom center" trigger="opened"> - -
-
- -
- - - -
-
- - -
- - - -
Hey there!
} pos="bottom center" trigger="opened"> - -
-
- -
- - - -
Hey there!
} pos="bottom center" trigger="opened"> - -
-
- -
- - - -
Hey there!
} pos="bottom center" trigger="opened"> - -
-
- -
- - - -
Hey there!
} pos="bottom center" trigger="opened"> - -
-
- -
- - - -
Hey there!
} pos="bottom center" trigger="opened"> - -
-
- -
- - - -
-
- -); -HintNearScreenEdge.storyName = 'hint near screen edge'; -HintNearScreenEdge.parameters = { - creevey: { - captureElement: 'body', - skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } }, - }, -}; diff --git a/packages/react-ui/components/Input/__stories__/Input.creevey.stories.tsx b/packages/react-ui/components/Input/__stories__/Input.creevey.stories.tsx deleted file mode 100644 index 872958f36c6..00000000000 --- a/packages/react-ui/components/Input/__stories__/Input.creevey.stories.tsx +++ /dev/null @@ -1,311 +0,0 @@ -// TODO: Rewrite stories and enable rule (in process of functional refactoring). -/* eslint-disable react/no-unstable-nested-components */ -import React, { useState } from 'react'; - -import { delay } from '../../../lib/utils'; -import { CreeveyTests, Meta, Story } from '../../../typings/stories'; -import { Input } from '../Input'; - -export default { - title: 'Input/Functional tests', - parameters: { - creevey: { - skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, - }, - }, -} as Meta; - -const differentStatesTest: CreeveyTests = { - async Plain() { - const element = await this.browser.findElement({ css: '#input' }); - await this.expect(await element.takeScreenshot()).to.matchImage('Plain'); - }, - async Focused() { - const element = await this.browser.findElement({ css: '#input' }); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#input input' })) - .pause(500) - .perform(); - await this.expect(await element.takeScreenshot()).to.matchImage('Focused'); - }, - async 'With typed text'() { - const element = await this.browser.findElement({ css: '#input' }); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#input input' })) - .sendKeys('Test...') - .pause(500) - .perform(); - await this.expect(await element.takeScreenshot()).to.matchImage('With typed text'); - }, - async 'With long typed text'() { - const element = await this.browser.findElement({ css: '#input' }); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#input input' })) - .sendKeys('Test...') - .sendKeys('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') - .pause(500) - .perform(); - await this.expect(await element.takeScreenshot()).to.matchImage('With long typed text'); - }, -}; - -export const Default: Story = () => ( -
- -
-); - -Default.parameters = { - creevey: { - tests: differentStatesTest, - }, -}; - -const testMaskedInput: CreeveyTests = { - async 'idle, focus, edit, blur'() { - const click = (css: string) => { - return this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css })); - }; - - const idle = await this.takeScreenshot(); - - await click('input').pause(500).perform(); - const focused = await this.takeScreenshot(); - - await click('input').sendKeys('953').perform(); - const edited = await this.takeScreenshot(); - - await click('body').perform(); - const blured = await this.takeScreenshot(); - - await this.expect({ idle, focused, edited, blured }).to.matchImages(); - }, -}; - -export const WithMask: Story = () => ( - -); -WithMask.parameters = { - creevey: { - tests: testMaskedInput, - }, -}; - -export const WithMaskAndCustomUnmaskedValue: Story = () => { - const [value, setValue] = useState('+795'); - - return ( - setValue(value.replace(/\s/g, ''))} - /> - ); -}; - -WithMaskAndCustomUnmaskedValue.parameters = { - creevey: { - skip: { - flaky: { in: ['firefox'] }, - }, - tests: testMaskedInput, - }, -}; - -export const SelectAllByProp: Story = () => ; - -SelectAllByProp.parameters = { - creevey: { - tests: { - async Plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); - }, - async Focused() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'label' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('Focused'); - }, - }, - }, -}; - -export const SelectAllByButton: Story = () => { - let input: Input | null = null; - - const selectAll = () => { - if (input) { - input.selectAll(); - } - }; - - return ( -
-
- (input = element)} defaultValue="Some value" /> -
- -
- ); -}; -SelectAllByButton.storyName = 'Select all by button'; - -SelectAllByButton.parameters = { - creevey: { - tests: { - async Plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); - }, - async Selected() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="select-all"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('Selected'); - }, - }, - }, -}; - -export const MaxLength: Story = () => ( -
- -
-); - -MaxLength.parameters = { creevey: { tests: differentStatesTest } }; - -export const UncontrolledInputWithPlaceholder: Story = () => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [_value, setValue] = React.useState(); - return setValue(value)} />; -}; -UncontrolledInputWithPlaceholder.storyName = 'Uncontrolled Input with Placeholder'; -UncontrolledInputWithPlaceholder.parameters = { - creevey: { - tests: { - async PlainAndTyped() { - const plain = await this.takeScreenshot(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'input' })) - .sendKeys('text') - .perform(); - const typed = await this.takeScreenshot(); - await this.expect({ plain, typed }).to.matchImages(); - }, - }, - }, -}; - -export const WithMaskAndSelectAllProp: Story = () => { - const inputRef = React.useRef(null); - const [value, setValue] = React.useState('11'); - const selectAll = React.useCallback(() => { - inputRef.current?.selectAll(); - }, [inputRef.current]); - return ( -
- -
- ); -}; - -WithMaskAndSelectAllProp.parameters = { - creevey: { - skip: { "themes don't affect logic": { in: /^(?!\bchrome\b)/ } }, - tests: { - async PlainAndSelected() { - const plain = await this.takeScreenshot(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'input' })) - .pause(500) - .perform(); - const selectAllHalfFilledInput = await this.takeScreenshot(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'input' })) - .sendKeys('1111') - .click(this.browser.findElement({ css: 'body' })) - .click(this.browser.findElement({ css: 'input' })) - .pause(500) - .perform(); - const selectAllFilledInput = await this.takeScreenshot(); - await this.expect({ plain, selectAllHalfFilledInput, selectAllFilledInput }).to.matchImages(); - }, - }, - }, -}; - -export const SearchTypeApi: Story = () => ; -SearchTypeApi.parameters = { - creevey: { - skip: { - 'tests only stable in chrome': { in: /^(?!\bchrome\b|\bchromeDark\b)/ }, - }, - tests: { - async Focused() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'label' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('Focused'); - }, - }, - }, -}; - -export const InputTypeApi: Story = () => ; -InputTypeApi.parameters = { - creevey: { - skip: { - "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b|\bchromeDark\b|\bfirefoxDark\b)/ }, - }, - tests: { - async Focused() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'label' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('Focused'); - }, - }, - }, -}; diff --git a/packages/react-ui/components/Input/__stories__/Input.stories.tsx b/packages/react-ui/components/Input/__stories__/Input.stories.tsx deleted file mode 100644 index 202da3ec182..00000000000 --- a/packages/react-ui/components/Input/__stories__/Input.stories.tsx +++ /dev/null @@ -1,383 +0,0 @@ -// TODO: Rewrite stories and enable rule (in process of functional refactoring). -/* eslint-disable react/no-unstable-nested-components */ -import React from 'react'; -import SearchIcon from '@skbkontur/react-icons/Search'; - -import { ComponentTable } from '../../../internal/ComponentTable'; -import { Meta, Story } from '../../../typings/stories'; -import { Input, InputProps } from '../Input'; -import { Gapped } from '../../Gapped'; - -export default { - title: 'Input', -} as Meta; - -type InputState = Partial; - -const sizeStates: InputState[] = [{ size: 'small' }, { size: 'medium' }, { size: 'large' }]; - -const inputDefaultState: InputState[] = [{}, { defaultValue: 'Value' }]; - -const inputWidthStates: InputState[] = [{}, { width: '100px' }, { width: '350px' }]; - -export const Align: Story = () => ( - ({ props: x }))} - rows={alignDifferentStates.map((x) => ({ props: x }))} - presetProps={{ value: 'Value', width: '200px' }} - /> -); - -const alignStates: InputState[] = [{ align: 'center' }, { align: 'left' }, { align: 'right' }]; - -const alignDifferentStates: InputState[] = [ - {}, - { leftIcon: }, - { rightIcon: }, - { prefix: 'PR' }, - { suffix: 'SF' }, - { leftIcon: , prefix: 'PR' }, - { leftIcon: , suffix: 'SF' }, - { rightIcon: , prefix: 'PR' }, - { rightIcon: , suffix: 'SF' }, - { leftIcon: , prefix: 'PR', suffix: 'SF' }, - { rightIcon: , prefix: 'PR', suffix: 'SF' }, -]; - -export const AlwaysShowMask: Story = () => ( - ({ props: x }))} - rows={alwaysShowMaskStates.map((x) => ({ props: x }))} - presetProps={{ mask: '(***) ***-**-**' }} - /> -); - -const alwaysShowMaskStates: InputState[] = [ - {}, - { defaultValue: '95678901' }, - { defaultValue: '956789010A' }, - { alwaysShowMask: true }, - { alwaysShowMask: true, defaultValue: '95678901' }, - { alwaysShowMask: true, defaultValue: '956789010A' }, -]; - -export const Borderless: Story = () => ( - ({ props: x }))} - rows={borderlessStates.map((x) => ({ props: x }))} - presetProps={{ borderless: true }} - /> -); - -const borderlessStates: InputState[] = [{}]; - -export const Disabled: Story = () => ( - ({ props: x }))} - rows={disabledStates.map((x) => ({ props: x }))} - presetProps={{ disabled: true }} - /> -); - -const disabledStates: InputState[] = [ - {}, - { value: 'Some text' }, - { placeholder: 'Placeholder' }, - { type: 'password', value: 'Value' }, - { leftIcon: }, - { rightIcon: }, - { prefix: 'PR' }, - { suffix: 'SF' }, -]; - -export const Error: Story = () => ( - ({ props: x }))} - rows={errorStates.map((x) => ({ props: x }))} - presetProps={{ error: true }} - /> -); -const errorStates: InputState[] = [{}, { borderless: true }, { disabled: true }]; - -export const LeftIcon: Story = () => ( - ({ props: x }))} - rows={iconsLeftStates.map((x) => ({ props: x }))} - presetProps={{ leftIcon: }} - /> -); - -export const RightIcon: Story = () => ( - ({ props: x }))} - rows={iconsRightStates.map((x) => ({ props: x }))} - presetProps={{ rightIcon: }} - /> -); - -const iconFunc = () => ; -iconFunc.toString = () => '() => '; - -const iconsStates: InputState[] = [{}, { defaultValue: 'Value' }, { disabled: true }]; - -const iconsLeftStates: InputState[] = [ - ...iconsStates, - { - leftIcon: iconFunc, - }, - { - leftIcon: '₽', - }, -]; - -const iconsRightStates: InputState[] = [ - ...iconsStates, - { - rightIcon: iconFunc, - }, - { - rightIcon: '₽', - }, -]; - -export const Mask: Story = () => ( - ({ props: x }))} - rows={maskStates.map((x) => ({ props: x }))} - presetProps={{}} - /> -); - -const maskStates: InputState[] = [ - { mask: '**** **********', alwaysShowMask: true }, - { mask: '**** **********', maskChar: '*', alwaysShowMask: true }, - { mask: '*** ***', maskChar: '_', defaultValue: 'Value' }, - { mask: '*** ***', maskChar: '_', defaultValue: 'Value', alwaysShowMask: true }, - { type: 'email', mask: '*** ***', maskChar: '_', defaultValue: 'Value', alwaysShowMask: true }, - { type: 'tel', mask: '*** ***', maskChar: '_', defaultValue: 'Value', alwaysShowMask: true }, - { type: 'url', mask: '*** ***', maskChar: '_', defaultValue: 'Value', alwaysShowMask: true }, - { type: 'search', mask: '*** ***', maskChar: '_', defaultValue: 'Value', alwaysShowMask: true }, - { type: 'date', mask: '*** ***', maskChar: '_', defaultValue: 'Value', alwaysShowMask: true }, - { type: 'time', mask: '*** ***', maskChar: '_', defaultValue: 'Value', alwaysShowMask: true }, - { type: 'number', mask: '*** ***', maskChar: '_', defaultValue: 'Value', alwaysShowMask: true }, - { mask: '*** ***', placeholder: 'ooo-long-long-long-placeholder' }, -]; - -export const Placeholder: Story = () => ( - ({ props: x }))} - rows={placeholderStates.map((x) => ({ props: x }))} - presetProps={{ placeholder: '1234567890' }} - /> -); - -const placeholderStates: InputState[] = [{}, { disabled: true }]; - -export const Prefix: Story = () => ( - ({ props: x }))} - rows={inputPrefixStates.map((x) => ({ props: x }))} - presetProps={{ prefix: 'Prefix' }} - /> -); -const inputPrefixOrSuffixStates: InputState[] = [ - {}, - { value: 'Value' }, - { placeholder: 'Placeholder' }, - { rightIcon: }, - { rightIcon: , value: 'Value' }, - { rightIcon: , placeholder: 'Placeholder' }, - { leftIcon: }, - { leftIcon: , value: 'Value' }, - { leftIcon: , placeholder: 'Placeholder' }, -]; - -const inputPrefixStates: InputState[] = [...inputPrefixOrSuffixStates, { prefix: 'ooo-long-long-long-johnson' }]; - -const inputSuffixStates: InputState[] = [...inputPrefixOrSuffixStates, { suffix: 'ooo-long-long-long-johnson' }]; - -export const Suffix: Story = () => ( - ({ props: x }))} - rows={inputSuffixStates.map((x) => ({ props: x }))} - presetProps={{ suffix: 'Suffix' }} - /> -); - -export const PrefixAndSuffixBoth: Story = () => ( - ({ props: x }))} - rows={inputPrefixOrSuffixStates.map((x) => ({ props: x }))} - presetProps={{ prefix: 'Prefix', suffix: 'Suffix' }} - /> -); - -export const Size: Story = () => ( - ({ props: x }))} - rows={inputDefaultState.map((x) => ({ props: x }))} - presetProps={{ children: 'Input' }} - /> -); - -export const TextStylesReset: Story = () => ( -
- - Inherited Styles - - - - - } prefix="Prefix" suffix="suffix" defaultValue="Value" /> - -
-); - -export const Type: Story = () => ( - ({ props: x }))} - rows={typeStates.map((x) => ({ props: x }))} - presetProps={{}} - /> -); -Type.parameters = { creevey: { skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } } } }; - -const typeStates: InputState[] = [ - { type: 'text', defaultValue: 'Value' }, - { type: 'password', defaultValue: 'Value' }, - { type: 'password', defaultValue: 'Value', disabled: true }, - { mask: '***-***', type: 'password', alwaysShowMask: true }, - { mask: '***-***', type: 'password', alwaysShowMask: true, defaultValue: 'Value' }, - { mask: '***-***', type: 'password', alwaysShowMask: true, defaultValue: 'Value', disabled: true }, - { type: 'number', defaultValue: '15', min: 10, max: 20, step: 5 }, - { type: 'search' }, - { type: 'date' }, - { type: 'time' }, - { type: 'email', pattern: '[a-z0-9._%+-]+@[a-z0-9.-]+.[a-z]{2,4}$' }, - { type: 'url' }, - { type: 'tel' }, -]; - -export const TypeApi: Story = () => ( - <> - ({ props: x }))} - rows={typeApiTypes.map((x) => ({ props: x }))} - presetProps={{}} - /> - ({ props: x }))} - rows={typeApiTypesDate.map((x) => ({ props: x }))} - presetProps={{}} - /> - ({ props: x }))} - rows={typeApiTypesTime.map((x) => ({ props: x }))} - presetProps={{}} - /> - -); -TypeApi.parameters = { - creevey: { skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } } }, -}; - -const typeApiTypes: InputState[] = [ - { type: 'number' }, - { type: 'search' }, - { type: 'email' }, - { type: 'url' }, - { type: 'tel' }, -]; -const typeApiTypesDate: InputState[] = [{ type: 'date' }]; -const typeApiTypesTime: InputState[] = [{ type: 'time' }]; - -const typeApiProps: InputState[] = [ - { leftIcon: , value: '123' }, - { rightIcon: , value: '123' }, - { rightIcon: , placeholder: 'placeholder' }, - { prefix: 'prefix: ' }, - { suffix: ' suffix' }, -]; -const typeApiPropsDate: InputState[] = [ - { rightIcon: }, - { leftIcon: }, - { value: '2022-05-04' }, - { prefix: 'prefix: ' }, - { suffix: ' suffix' }, -]; -const typeApiPropsTime: InputState[] = [ - { rightIcon: }, - { leftIcon: }, - { value: '18:00' }, - { prefix: 'prefix: ' }, - { suffix: ' suffix' }, -]; - -export const Warning: Story = () => ( - ({ props: x }))} - rows={warningStates.map((x) => ({ props: x }))} - presetProps={{ warning: true }} - /> -); - -const warningStates: InputState[] = [{}, { borderless: true }, { disabled: true }]; - -export const BlinkingByButton: Story = () => { - class Sample extends React.Component { - private input: Input | null = null; - - public render() { - return ( - - - - - ); - } - - private handleClick = () => { - if (this.input) { - this.input.blink(); - } - }; - - private refInput = (element: Input | null) => { - this.input = element; - }; - } - - return ; -}; -BlinkingByButton.parameters = { creevey: { skip: true } }; diff --git a/packages/react-ui/components/Kebab/__stories__/Kebab.creevey.stories.tsx b/packages/react-ui/components/Kebab/__stories__/Kebab.creevey.stories.tsx deleted file mode 100644 index 06ce47316df..00000000000 --- a/packages/react-ui/components/Kebab/__stories__/Kebab.creevey.stories.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import React from 'react'; -import OkIcon from '@skbkontur/react-icons/Ok'; - -import { delay } from '../../../lib/utils'; -import { CreeveyTests, Meta } from '../../../typings/stories'; -import { MenuHeader } from '../../../components/MenuHeader'; -import { MenuItem } from '../../../components/MenuItem'; -import { PopupMenuDataTids } from '../../../internal/PopupMenu'; -import { Kebab } from '../Kebab'; - -export default { - title: 'Kebab/Functional tests', - decorators: [ - (Story: () => JSX.Element) => ( -
- -
- ), - ], - parameters: { - creevey: { - skip: { "themes don't affect logic": { in: /^(?!\bchrome\b)/ } }, - }, - }, -} as Meta; - -const textAlignmentTests: CreeveyTests = { - async opened() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: `[data-tid~="${PopupMenuDataTids.caption}"]` })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened'); - }, -}; - -export const WithItemsAndIcons = () => ( -
- - MenuHeader - }>MenuItem1 - }>MenuItem2 - MenuItem3 - -
-); -WithItemsAndIcons.parameters = { - creevey: { - tests: textAlignmentTests, - skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, - }, -}; - -export const WithItemsAndIconsWithoutTextAlignment = () => ( -
- - MenuHeader - }>MenuItem1 - }>MenuItem2 - MenuItem3 - -
-); -WithItemsAndIconsWithoutTextAlignment.parameters = { - creevey: { - tests: textAlignmentTests, - skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, - }, -}; diff --git a/packages/react-ui/components/Kebab/__stories__/Kebab.items.tsx b/packages/react-ui/components/Kebab/__stories__/Kebab.items.tsx deleted file mode 100644 index f79ea3bb1a7..00000000000 --- a/packages/react-ui/components/Kebab/__stories__/Kebab.items.tsx +++ /dev/null @@ -1,53 +0,0 @@ -export const defaultItemsList = [ - { - text: 'First', - action: 'First', - }, - { - text: 'Second', - action: 'Second', - }, - { - text: 'Uno', - action: 'Uno', - }, -]; - -export const manyItemsList = [ - { - text: 'Edit', - action: 'Edit', - }, - { - text: 'Remove', - action: 'Remove', - }, - { - text: 'Communicate', - action: 'Communicate', - }, - { - text: 'Grade', - action: 'Grade', - }, - { - text: 'Dispatch', - action: 'Dispatch', - }, - { - text: 'Disable', - action: 'Disable', - }, - { - text: 'Rate', - action: 'Rate', - }, - { - text: 'Collaborate', - action: 'Collaborate', - }, - { - text: 'Contribute', - action: 'Contribute', - }, -]; diff --git a/packages/react-ui/components/Kebab/__stories__/Kebab.stories.tsx b/packages/react-ui/components/Kebab/__stories__/Kebab.stories.tsx deleted file mode 100644 index 1a8cd302536..00000000000 --- a/packages/react-ui/components/Kebab/__stories__/Kebab.stories.tsx +++ /dev/null @@ -1,253 +0,0 @@ -import React from 'react'; -import { action } from '@storybook/addon-actions'; -import OkIcon from '@skbkontur/react-icons/Ok'; - -import { ReactUIFeatureFlagsContext } from '../../../lib/featureFlagsContext'; -import { Meta, Story, CreeveyTests } from '../../../typings/stories'; -import { Kebab } from '../Kebab'; -import { MenuItem } from '../../MenuItem'; -import { KebabProps } from '..'; -import { delay } from '../../../lib/utils'; - -import { defaultItemsList, manyItemsList } from './Kebab.items'; - -interface KebabItem { - text: string; - action: string; -} - -const kebabTests: CreeveyTests = { - async plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('plain'); - }, - async hovered() { - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: '[data-comp-name~="Kebab"]' }), - }) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); - }, - async clicked() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Kebab"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); - }, - async clickedOnButton2ndTime() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Kebab"]' })) - .click(this.browser.findElement({ css: '[data-comp-name~="Kebab"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('clickedOnButton2ndTime'); - }, - async tabPress() { - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); - }, - async enterPress() { - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .sendKeys(this.keys.ENTER) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('enterPress'); - }, -}; - -export default { - title: 'Kebab', - decorators: [ - (Story: () => JSX.Element) => ( -
- -
- ), - ], -} as Meta; - -export const Small: Story = () => ; -Small.storyName = '14px'; - -Small.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'hovered' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { - in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], - tests: ['hovered', 'clickedOnButton2ndTime'], - }, - }, - tests: kebabTests, - }, -}; - -export const Medium: Story = () => ; -Medium.storyName = '18px'; - -Medium.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'hovered' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { - in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], - tests: ['hovered', 'clickedOnButton2ndTime'], - }, - }, - tests: kebabTests, - }, -}; - -export const Large: Story = () => ; -Large.storyName = '20px'; - -Large.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'hovered' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { - in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], - tests: ['hovered', 'clickedOnButton2ndTime'], - }, - }, - tests: kebabTests, - }, -}; - -export const KebabHintRemovePinFeatureFlag: Story = () => { - return ( - - - - ); -}; -KebabHintRemovePinFeatureFlag.storyName = 'with kebabHintRemovePin feature flag'; -KebabHintRemovePinFeatureFlag.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: /^(?!\b.*2022.*\b)/ }, - 'story-skip-1': { - in: /(?!\b.*2022.*\b)/, - tests: ['plain', 'hovered', 'clickedOnButton2ndTime', 'tabPress', 'enterPress'], - }, - }, - tests: kebabTests, - }, -}; - -export const KebabWithCustomIcon: Story = () => { - return ( - <> - } /> - } /> - } /> - - ); -}; - -export const LargeDisabled = () => ; -LargeDisabled.storyName = '20px-disabled'; -LargeDisabled.parameters = { creevey: { skip: true } }; - -export const WithFixedMenuHeight = () => ( - -); -WithFixedMenuHeight.storyName = 'With fixed menu height'; -WithFixedMenuHeight.parameters = { creevey: { skip: true } }; - -export const KebabWithoutAnimations = () => ; -KebabWithoutAnimations.storyName = 'Kebab without animations'; -KebabWithoutAnimations.parameters = { creevey: { skip: true } }; - -interface SomethingWithKebabProps { - items?: KebabItem[]; - disableAnimations?: boolean; - size: KebabProps['size']; - disabled?: boolean; - menuMaxHeight?: number | string; - icon?: React.ReactNode; -} -class SomethingWithKebab extends React.Component { - public render() { - const itemsList = this.props.items || defaultItemsList; - const menuItems = itemsList.map((item: KebabItem, index: number) => { - return ( - - {item.text} - - ); - }); - - return ( -
- Pikachu{' '} - - {menuItems} - -
- ); - } -} - -export const MobileExampleWithHorizontalPadding: Story = () => ; - -MobileExampleWithHorizontalPadding.parameters = { - viewport: { - defaultViewport: 'iphone', - }, - creevey: { - captureElement: null, - tests: { - async opened() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-comp-name~="Kebab"]' })) - .perform(); - await delay(200); - await this.browser - .actions({ bridge: true }) - .move({ origin: this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' }) }) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened'); - }, - }, - }, -}; diff --git a/packages/react-ui/components/Link/__stories__/Link.stories.tsx b/packages/react-ui/components/Link/__stories__/Link.stories.tsx deleted file mode 100644 index 2c1fd4279c6..00000000000 --- a/packages/react-ui/components/Link/__stories__/Link.stories.tsx +++ /dev/null @@ -1,249 +0,0 @@ -import React from 'react'; -import OkIcon from '@skbkontur/react-icons/Ok'; -import { CheckAIcon16Light } from '@skbkontur/icons/icons/CheckAIcon'; - -import { Story, CreeveyTests } from '../../../typings/stories'; -import { Link } from '../Link'; -import { Toast } from '../../Toast'; -import { Gapped } from '../../Gapped'; -import { delay } from '../../../lib/utils'; -import { ThemeContext } from '../../../lib/theming/ThemeContext'; -import { ThemeFactory } from '../../../lib/theming/ThemeFactory'; -import { ReactUIFeatureFlagsContext } from '../../../lib/featureFlagsContext'; - -const linkTests: CreeveyTests = { - async idle() { - await this.expect(await this.takeScreenshot()).to.matchImage('idle'); - }, - async hover() { - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: 'a' }), - }) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('hover'); - }, -}; - -export default { - title: 'Link', - parameters: { - creevey: { - skip: { - 'kind-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'hover' }, - }, - }, - }, -}; - -const focusedLinkTest: CreeveyTests = { - async 'tab press'() { - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .perform(); - await delay(1000); - await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: 'a' }), - }) - .perform(); - await delay(1000); - await this.expect(await this.takeScreenshot()).to.matchImage('tabPressHovered'); - }, -}; - -export const Simple: Story = () => Simple Link; -Simple.parameters = { - creevey: { - tests: linkTests, - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, - }, - }, -}; - -export const WithIcon: Story = () => { - return ( - - - }>Left Icon Link - } rightIcon={}> - Both Icons Link - - }>Right Icon Link - - - }> - Left Icon Link - - } rightIcon={}> - Both Icons Link - - }> - Right Icon Link - - - - ); -}; -WithIcon.parameters = { - creevey: { - tests: { - idle: linkTests['idle'], - hover: linkTests['hover'], - 'tab press': focusedLinkTest['tab press'], - }, - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, - 'story-skip-1': { in: /^(?!\b(chrome|firefox)(2022)*(Dark)*\b)/, tests: ['tab press'] }, - }, - }, -}; - -export const Danger: Story = () => ( - } use="danger"> - Simple Link - -); -Danger.parameters = { - creevey: { - tests: linkTests, - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, - }, - }, -}; - -export const Grayed: Story = () => Simple link; -Grayed.parameters = { - creevey: { - tests: linkTests, - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, - }, - }, -}; - -export const Disabled: Story = () => Simple link; -Disabled.parameters = { - creevey: { - tests: linkTests, - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, - }, - }, -}; - -export const WithOnClick = () => Toast.push('Clicked!')}>Simple Link; -WithOnClick.storyName = 'With onClick'; -WithOnClick.parameters = { creevey: { skip: true } }; - -export const Loading: Story = () => ( - - Simple loading -
- {'Some long text '} - loading link - and end of line -
-
- {'Some long text '} - loading link - and end of line -
- }> - Loading link with icon - -
-); -Loading.parameters = { - creevey: { - tests: linkTests, - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, - }, - }, -}; - -const focusedStyledLinkTest: CreeveyTests = { - async 'tab press'() { - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: 'a' }), - }) - .perform(); - await delay(1000); - await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: 'a' }), - }) - .perform(); - await delay(1000); - await this.expect(await this.takeScreenshot()).to.matchImage('tabPressHovered'); - }, -}; -export const FocusedStyledLink: Story = () => { - return ( - - {(theme) => { - return ( - - }>Simple Link - - ); - }} - - ); -}; -FocusedStyledLink.parameters = { - creevey: { - tests: focusedStyledLinkTest, - skip: { flacky: { in: /^(?!\b(firefox2022)\b)/ } }, - }, -}; - -export const WithLinkFocusOutlineFeatureFlag = () => ( - - Link - -); - -WithLinkFocusOutlineFeatureFlag.parameters = { - creevey: { - tests: focusedStyledLinkTest, - skip: { - 'hover does not work': { - in: /chrome/, - }, - }, - }, -}; diff --git a/packages/react-ui/components/Loader/__stories__/Loader.stories.tsx b/packages/react-ui/components/Loader/__stories__/Loader.stories.tsx deleted file mode 100644 index 485d59c8b17..00000000000 --- a/packages/react-ui/components/Loader/__stories__/Loader.stories.tsx +++ /dev/null @@ -1,371 +0,0 @@ -import React, { useState } from 'react'; - -import { AnyObject } from '../../../lib/utils'; -import { Story } from '../../../typings/stories'; -import { Loader, LoaderProps } from '../Loader'; -import { css } from '../../../lib/theming/Emotion'; -import { EyeOpenedIcon } from '../../../internal/icons/16px/index'; -import { ThemeContext } from '../../../lib/theming/ThemeContext'; -import { Toggle } from '../../Toggle'; - -import { LoaderAndButton } from './LoaderAndButton'; - -const loaderClass = css` - height: 100%; -`; - -const wrapperStyle = { - width: '800px', - background: 'AliceBlue', -}; - -const darkWrapperStyle = { - ...wrapperStyle, - background: '#1f1f1f', -}; - -interface ContentComponentProps { - additionalStyle?: AnyObject; - loaderProps?: Partial; -} -class ContentComponent extends React.Component> { - public render() { - const { additionalStyle, loaderProps, children } = this.props; - return ( - - {(theme) => { - return ( -
- - {children} - -
- ); - }} -
- ); - } -} - -interface NumberListProps { - itemsCount: number; -} -class NumberList extends React.Component { - public render() { - return ( - <> - {this.getItems(this.props.itemsCount).map((i) => ( -
{i}
- ))} - - ); - } - - private getItems(count: number) { - const items = []; - for (let i = 0; i < count; i += 1) { - items.push(i); - } - return items; - } -} - -export default { title: 'Loader' }; - -export const Simple = () => { - const [toggleValue, setToggleValue] = useState(false); - return ( - <> - setToggleValue(v)} /> - -
- Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut - labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut - aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore - eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt - mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor - incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco - laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit - esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui - officia deserunt mollit anim id est laborum. -
-
- - ); -}; -Simple.parameters = { creevey: { skip: true } }; - -export const TypeBig = () => ( - - - -); -TypeBig.storyName = 'Type "big"'; -TypeBig.parameters = { creevey: { skip: true } }; - -export const TypeBigWithText = () => ( -
-

- Yeah, and if you were the pope they'd be all, "Straighten your pope hat." And "Put on your - good vestments." -

-

- No, I'm Santa Claus! I guess if you want children beaten, you have to do it yourself. We're also Santa - Claus! Leela, Bender, we're going grave robbing. -

-

- Are you crazy? I can't swallow that. Large bet on myself in round one. Hey, whatcha watching?{' '} - Moving along… I guess if you want children beaten, you have to do it yourself. - It's okay, Bender. I like cooking too. -

-

Oh, I think we should just stay friends.

-

- No argument here. And when we woke up, we had these bodies. You guys go on without me! I'm going to go… look - for more stuff to steal! Oh, how awful. Did he at least die painlessly? …To shreds, you say. Well, how is his wife - holding up? …To shreds, you say. -

-
    -
  1. No! The kind with looting and maybe starting a few fires!
  2. -
  3. You are the last hope of the universe.
  4. -
  5. Hey, guess what you're accessories to.
  6. -
- -

- Yeah, and if you were the pope they'd be all, "Straighten your pope hat." And "Put on your - good vestments." -

-

- No, I'm Santa Claus! I guess if you want children beaten, you have to do it yourself. We're also Santa - Claus! Leela, Bender, we're going grave robbing. -

-

- Are you crazy? I can't swallow that. Large bet on myself in round one. Hey, whatcha watching?{' '} - Moving along… I guess if you want children beaten, you have to do it yourself. - It's okay, Bender. I like cooking too. -

-

Oh, I think we should just stay friends.

-

- No argument here. And when we woke up, we had these bodies. You guys go on without me! I'm going to go… - look for more stuff to steal! Oh, how awful. Did he at least die painlessly? …To shreds, you say. Well, how is - his wife holding up? …To shreds, you say. -

-
    -
  1. No! The kind with looting and maybe starting a few fires!
  2. -
  3. You are the last hope of the universe.
  4. -
  5. Hey, guess what you're accessories to.
  6. -
-
-

- Yeah, and if you were the pope they'd be all, "Straighten your pope hat." And "Put on your - good vestments." -

-

- No, I'm Santa Claus! I guess if you want children beaten, you have to do it yourself. We're also Santa - Claus! Leela, Bender, we're going grave robbing. -

-

- Are you crazy? I can't swallow that. Large bet on myself in round one. Hey, whatcha watching?{' '} - Moving along… I guess if you want children beaten, you have to do it yourself. - It's okay, Bender. I like cooking too. -

-

Oh, I think we should just stay friends.

-

- No argument here. And when we woke up, we had these bodies. You guys go on without me! I'm going to go… look - for more stuff to steal! Oh, how awful. Did he at least die painlessly? …To shreds, you say. Well, how is his wife - holding up? …To shreds, you say. -

-
    -
  1. No! The kind with looting and maybe starting a few fires!
  2. -
  3. You are the last hope of the universe.
  4. -
  5. Hey, guess what you're accessories to.
  6. -
-
-); -TypeBigWithText.storyName = 'Type "big" with text'; -TypeBigWithText.parameters = { creevey: { skip: true } }; - -export const VerticalScroll = () => ( - - - -); -VerticalScroll.storyName = 'Vertical scroll'; -VerticalScroll.parameters = { creevey: { skip: true } }; - -export const HorizontalScroll = () => ( - - - -); -HorizontalScroll.storyName = 'Horizontal scroll'; -HorizontalScroll.parameters = { creevey: { skip: true } }; - -export const BothDimensionsScrollableContentWithSpacesAround = () => ( - - - -); -BothDimensionsScrollableContentWithSpacesAround.storyName = 'Both dimensions scrollable content with spaces around'; -BothDimensionsScrollableContentWithSpacesAround.parameters = { creevey: { skip: true } }; - -export const ActiveLoader: Story = () => ; -ActiveLoader.storyName = 'Active loader'; - -ActiveLoader.parameters = { - creevey: { - tests: { - async 'covers children'() { - const element = await this.browser.findElement({ css: '[data-comp-name~="Loader"]' }); - const button = await this.browser.findElement({ css: '[data-comp-name~="Button"]' }); - - await this.browser.actions({ bridge: true }).click(button).perform(); - - await this.expect(await element.takeScreenshot()).to.matchImage('cover children'); - }, - }, - }, -}; - -export const InactiveLoader: Story = () => ; -InactiveLoader.storyName = 'Inactive loader'; - -InactiveLoader.parameters = { - creevey: { - tests: { - async "doesn't cover children"() { - const element = await this.browser.findElement({ css: '[data-comp-name~="Loader"]' }); - const button = await this.browser.findElement({ css: '[data-comp-name~="Button"]' }); - - await this.browser.actions({ bridge: true }).click(button).perform(); - - await this.expect(await element.takeScreenshot()).to.matchImage("doesn't cover children"); - }, - }, - }, -}; - -export const WrapperWithCustomHeightAndInactiveLoader = () => ( - - {(theme) => { - return ( - -
- -
-
- ); - }} -
-); -WrapperWithCustomHeightAndInactiveLoader.storyName = 'Wrapper with custom height and inactive loader'; - -export const WrapperWithCustomHeightAndActiveLoader = () => ( - - {(theme) => { - return ( - -
- -
-
- ); - }} -
-); -WrapperWithCustomHeightAndActiveLoader.storyName = 'Wrapper with custom height and active loader'; - -export const ActivateLoaderAfterMountOnLargeContent = () => { - const [active, setActive] = React.useState(false); - React.useEffect(() => { - setActive(true); - }, []); - - return ( - - - - ); -}; - -export const WithCustomComponent: Story = () => { - const getTestComponent = () => { - return ( -
- - Загрузка -
- ); - }; - - const testText = 'Lorem ipsum dolor sit '.repeat(40); - - return ( -
- - {testText} - -
- - {testText} - -
- - {testText} - -
- ); -}; - -export const FocusInside: Story = () => { - const [active, setActive] = React.useState(false); - return ( -
- - - - -
- ); -}; -FocusInside.parameters = { - creevey: { - tests: { - async 'focus inside'() { - const loader = await this.browser.findElement({ css: '[data-comp-name~="Loader"]' }); - const toggle = await this.browser.findElement({ css: '[data-tid~="toggle-loader"]' }); - - await this.browser.actions().sendKeys(this.keys.TAB).perform(); - const enabled = await loader.takeScreenshot(); - - await this.browser.actions().click(toggle).move({ x: 0, y: 0 }).click().perform(); - - await this.browser.actions().sendKeys(this.keys.TAB).perform(); - const disabled = await loader.takeScreenshot(); - - await this.expect({ enabled, disabled }).to.matchImages(); - }, - }, - }, -}; diff --git a/packages/react-ui/components/Loader/__stories__/LoaderAndButton.tsx b/packages/react-ui/components/Loader/__stories__/LoaderAndButton.tsx deleted file mode 100644 index 441146a5b18..00000000000 --- a/packages/react-ui/components/Loader/__stories__/LoaderAndButton.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React from 'react'; - -import { Tooltip } from '../../Tooltip'; -import { Button } from '../../Button'; -import { Loader } from '../Loader'; -import { LoaderProps } from '..'; - -type LoaderAndButtonProps = Pick; -interface LoaderAndButtonState { - isTooltipOpened: boolean; - isActive?: boolean; -} -export class LoaderAndButton extends React.Component { - public state: LoaderAndButtonState = { - isTooltipOpened: false, - }; - - public render() { - return ( - -

- Yeah, and if you were the pope they'd be all, "Straighten your pope hat." And "Put on your - good vestments." -

- 'Yes, you can!'} trigger={this.state.isTooltipOpened ? 'opened' : 'closed'}> - - -

- No, I'm Santa Claus! I guess if you want children beaten, you have to do it yourself. We're also - Santa Claus! Leela, Bender, we're going grave robbing. -

-

- Are you crazy? I can't swallow that. Large bet on myself in round one. Hey, whatcha watching?{' '} - Moving along… I guess if you want children beaten, you have to do it yourself. - It's okay, Bender. I like cooking too. -

-

Oh, I think we should just stay friends.

-

- No argument here. And when we woke up, we had these bodies. You guys go on without me! I'm going to go… - look for more stuff to steal! Oh, how awful. Did he at least die painlessly? …To shreds, you say. Well, how is - his wife holding up? …To shreds, you say. -

-
    -
  1. No! The kind with looting and maybe starting a few fires!
  2. -
  3. You are the last hope of the universe.
  4. -
  5. Hey, guess what you're accessories to.
  6. -
-
- ); - } -} diff --git a/packages/react-ui/components/MaskedInput/__stories__/MaskedInput.creevey.stories.tsx b/packages/react-ui/components/MaskedInput/__stories__/MaskedInput.creevey.stories.tsx deleted file mode 100644 index 77d2b59ca6d..00000000000 --- a/packages/react-ui/components/MaskedInput/__stories__/MaskedInput.creevey.stories.tsx +++ /dev/null @@ -1,239 +0,0 @@ -// TODO: Rewrite stories and enable rule (in process of functional refactoring). -/* eslint-disable react/no-unstable-nested-components */ -import React, { useState } from 'react'; - -import { CreeveyTests, Meta, Story } from '../../../typings/stories'; -import { MaskedInput } from '../MaskedInput'; -import { Input } from '../../Input'; - -export default { - title: 'MaskedInput/Functional tests', - parameters: { - creevey: { - skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, - }, - }, -} as Meta; - -const testMaskedInput: CreeveyTests = { - async 'idle, focus, edit, blur'() { - const click = (css: string) => { - return this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css })); - }; - - const idle = await this.takeScreenshot(); - - await click('input').pause(500).perform(); - const focused = await this.takeScreenshot(); - - await click('input').sendKeys('953').perform(); - const edited = await this.takeScreenshot(); - - await click('body').perform(); - const blured = await this.takeScreenshot(); - - await this.expect({ idle, focused, edited, blured }).to.matchImages(); - }, -}; - -export const Default: Story = () => ( - -); -Default.parameters = { - creevey: { - tests: testMaskedInput, - }, -}; - -const testIdleFocusBlur: CreeveyTests = { - async 'idle, focus, blur'() { - const click = (css: string) => { - return this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css })); - }; - - const idle = await this.takeScreenshot(); - - await click('input').pause(500).perform(); - const focused = await this.takeScreenshot(); - - await click('body').perform(); - const blured = await this.takeScreenshot(); - - await this.expect({ idle, focused, blured }).to.matchImages(); - }, -}; - -export const IdleFocusBlur: Story = () => ( - -); - -IdleFocusBlur.parameters = { - creevey: { - tests: testIdleFocusBlur, - }, -}; - -export const IdleFocusBlurWithPrefix: Story = () => ( - -); - -IdleFocusBlurWithPrefix.parameters = { - creevey: { - tests: testIdleFocusBlur, - }, -}; - -export const WithCustomUnmaskedValue: Story = () => { - const [value, setValue] = useState('+795'); - - return ( - setValue(value.replace(/\s/g, ''))} - /> - ); -}; - -WithCustomUnmaskedValue.parameters = { - creevey: { - tests: testMaskedInput, - }, -}; - -export const SelectAllByProp: Story = () => ( - -); - -SelectAllByProp.parameters = { - creevey: { - tests: { - async 'Plain focused'() { - const plain = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'label' })) - .perform(); - - const focused = await this.takeScreenshot(); - await this.expect({ plain, focused }).to.matchImages(); - }, - }, - }, -}; - -export const SelectAllByButton: Story = () => { - let input: Input | null = null; - - const selectAll = () => { - if (input) { - input.selectAll(); - } - }; - - return ( -
-
- (input = element)} mask={'99:99'} defaultValue="12:34" /> -
- -
- ); -}; -SelectAllByButton.storyName = 'Select all by button'; - -SelectAllByButton.parameters = { - creevey: { - tests: { - async 'Plain, selected'() { - const plain = await this.takeScreenshot(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="select-all"]' })) - .perform(); - const selected = await this.takeScreenshot(); - - await this.expect({ plain, selected }).to.matchImages(); - }, - }, - }, -}; - -export const UncontrolledInputWithPlaceholder: Story = () => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [_value, setValue] = React.useState(); - return setValue(value)} />; -}; -UncontrolledInputWithPlaceholder.storyName = 'Uncontrolled Input with Placeholder'; -UncontrolledInputWithPlaceholder.parameters = { - creevey: { - tests: { - async PlainAndTyped() { - const plain = await this.takeScreenshot(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'input' })) - .sendKeys('text') - .perform(); - const typed = await this.takeScreenshot(); - await this.expect({ plain, typed }).to.matchImages(); - }, - }, - }, -}; - -const testRewriteInMiddle: CreeveyTests = { - async 'idle, shift, rewrite'() { - const idle = await this.takeScreenshot(); - - const input = await this.browser.findElement({ css: 'input' }); - this.browser - .actions({ bridge: true }) - .click(input) - .keyDown(this.keys.ARROW_LEFT) - .keyDown(this.keys.ARROW_LEFT) - .sendKeys('12') - .perform(); - const shift = await this.takeScreenshot(); - - this.browser - .actions({ bridge: true }) - .click(input) - .keyDown(this.keys.ARROW_LEFT) - .keyDown(this.keys.ARROW_LEFT) - .sendKeys('56') - .perform(); - const rewrite = await this.takeScreenshot(); - - await this.expect({ idle, shift, rewrite }).to.matchImages(); - }, -}; - -export const RewriteInMiddle: Story = () => ; - -RewriteInMiddle.parameters = { - creevey: { - tests: testRewriteInMiddle, - }, -}; diff --git a/packages/react-ui/components/MaskedInput/__stories__/MaskedInput.stories.tsx b/packages/react-ui/components/MaskedInput/__stories__/MaskedInput.stories.tsx deleted file mode 100644 index 9274eb06986..00000000000 --- a/packages/react-ui/components/MaskedInput/__stories__/MaskedInput.stories.tsx +++ /dev/null @@ -1,128 +0,0 @@ -// TODO: Rewrite stories and enable rule (in process of functional refactoring). -/* eslint-disable react/no-unstable-nested-components */ -import React from 'react'; -import SearchIcon from '@skbkontur/react-icons/Search'; - -import { ComponentTable } from '../../../internal/ComponentTable'; -import { Meta, Story } from '../../../typings/stories'; -import { MaskedInput, MaskedInputProps } from '../MaskedInput'; - -export default { - title: 'MaskedInput', -} as Meta; - -type InputState = Partial; - -const sizeStates: InputState[] = [{ size: 'small' }, { size: 'medium' }, { size: 'large' }]; - -export const Mask: Story = () => ( - ({ props: x }))} - rows={maskStates.map((x) => ({ props: x }))} - presetProps={{ mask: '(999) 999-99-99' }} - /> -); - -const maskStates: InputState[] = [ - {}, - { defaultValue: '95678901' }, - { defaultValue: '956789010A' }, - { mask: '****', value: 'overflow' }, - { placeholder: 'mask with placeholder' }, - { alwaysShowMask: true }, - { alwaysShowMask: true, maskChar: null }, - { alwaysShowMask: true, maskChar: 'X' }, - { alwaysShowMask: true, defaultValue: '95678901' }, - { alwaysShowMask: true, defaultValue: '956789010A' }, - { alwaysShowMask: true, placeholder: 'mask with placeholder' }, - { alwaysShowMask: true, type: 'email', mask: '*** ***', defaultValue: 'Value' }, - { alwaysShowMask: true, type: 'tel', mask: '*** ***', defaultValue: 'Value' }, - { alwaysShowMask: true, type: 'url', mask: '*** ***', defaultValue: 'Value' }, - { alwaysShowMask: true, type: 'search', mask: '*** ***', defaultValue: 'Value' }, -]; - -export const PrefixOrSuffix: Story = () => ( - ({ props: x }))} - rows={inputPrefixOrSuffixStates.map((x) => ({ props: x }))} - presetProps={{ mask: '+7 (999) 999 99 99' }} - /> -); -const inputPrefixOrSuffixStates: InputState[] = [ - {}, - { rightIcon: }, - { rightIcon: , value: '+79876543210' }, - { leftIcon: }, - { leftIcon: , value: '+79876543210' }, - { rightIcon: , placeholder: 'Placeholder' }, - { leftIcon: , placeholder: 'Placeholder' }, - { prefix: 'prefix:' }, - { prefix: 'prefix:', value: '+79876543210' }, - { suffix: '/suffix' }, - { suffix: '/suffix', value: '+79876543210' }, -]; - -export const PrefixesAndSuffixes: Story = () => ( - ({ props: x }))} - presetProps={{ mask: '+7 (999) 999 99 99', width: '250px' }} - /> -); -const prefixesAndSuffixesStates: InputState[] = [ - { - rightIcon: , - leftIcon: , - prefix: 'prefix:', - suffix: '/suffix', - placeholder: 'Placeholder', - }, - { - rightIcon: , - leftIcon: , - prefix: 'prefix:', - suffix: '/suffix', - value: '+7987654321', - alwaysShowMask: true, - }, -]; - -export const Validations: Story = () => ( - ({ props: x }))} - rows={validationsStates.map((x) => ({ props: x }))} - presetProps={{ mask: '99:99' }} - /> -); - -const validationsStates: InputState[] = [ - {}, - { borderless: true }, - { disabled: true }, - { alwaysShowMask: true, disabled: true }, - { warning: true }, - { error: true }, -]; - -export const Positions: Story = () => ( - ({ props: x }))} - rows={positionsStates.map((x) => ({ props: x }))} - presetProps={{ alwaysShowMask: true, mask: '**** **** ****' }} - /> -); - -const positionsStates: InputState[] = [ - { value: '1' }, - { value: '1111 1' }, - { value: '1111 1111 111' }, - { value: 'W' }, - { value: 'WWWW W' }, - { value: 'WWWW WWWW WWW' }, - { value: 'W1W1 W1W1 W1' }, -]; diff --git a/packages/react-ui/components/MenuFooter/__stories__/MenuFooter.stories.tsx b/packages/react-ui/components/MenuFooter/__stories__/MenuFooter.stories.tsx deleted file mode 100644 index d4051634436..00000000000 --- a/packages/react-ui/components/MenuFooter/__stories__/MenuFooter.stories.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; - -import { Meta } from '../../../typings/stories'; -import { MenuFooter } from '../MenuFooter'; -import { Gapped } from '../../Gapped'; - -export default { - title: 'MenuFooter', -} as Meta; - -export const Size = () => { - return ( - - Маленький - Средний - Большой - - ); -}; -Size.storyName = 'size'; diff --git a/packages/react-ui/components/MenuHeader/__stories__/MenuHeader.stories.tsx b/packages/react-ui/components/MenuHeader/__stories__/MenuHeader.stories.tsx deleted file mode 100644 index 50b2173db57..00000000000 --- a/packages/react-ui/components/MenuHeader/__stories__/MenuHeader.stories.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; - -import { Meta } from '../../../typings/stories'; -import { MenuHeader } from '../MenuHeader'; -import { Gapped } from '../../Gapped'; - -export default { - title: 'MenuHeader', -} as Meta; - -export const Size = () => { - return ( - - Маленький - Средний - Большой - - ); -}; -Size.storyName = 'size'; diff --git a/packages/react-ui/components/MenuItem/__stories__/MenuItem.stories.tsx b/packages/react-ui/components/MenuItem/__stories__/MenuItem.stories.tsx deleted file mode 100644 index dacfb2c8de7..00000000000 --- a/packages/react-ui/components/MenuItem/__stories__/MenuItem.stories.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react'; -import OkIcon from '@skbkontur/react-icons/Ok'; - -import { ThemeContext } from '../../../lib/theming/ThemeContext'; -import { ThemeFactory } from '../../../lib/theming/ThemeFactory'; -import { Meta } from '../../../typings/stories'; -import { MenuItem } from '../MenuItem'; -import { Gapped } from '../../Gapped'; - -export default { - title: 'MenuItem', -} as Meta; - -export const MobileMenuItemWithIcon = () => { - return ( - } isMobile> - Мобильный айтем с иконкой - - ); -}; -MobileMenuItemWithIcon.storyName = 'mobile menu item with icon'; - -export const MenuItemWithIcon = () => { - return }>Меню айтем с иконкой; -}; -MenuItemWithIcon.storyName = 'menu item with icon'; -MenuItemWithIcon.parameters = { - creevey: { - skip: { in: /^(?!\bchrome\b)/ }, - }, -}; - -export const MenuItemWithBiggerFontSize = () => { - return ( - - {(theme) => ( - - }>Меню айтем с увеличенным размером шрифта - - )} - - ); -}; -MenuItemWithBiggerFontSize.storyName = 'menu item with bigger font size'; -MenuItemWithBiggerFontSize.parameters = { - creevey: { - skip: { in: /^(?!\bchrome\b)/ }, - }, -}; - -export const Size = () => { - const comment = Комментарий; - return ( - - } comment={comment}> - Без размера - - } comment={comment}> - Маленький - - } comment={comment}> - Средний - - } comment={comment}> - Большой - - - ); -}; -Size.storyName = 'size'; diff --git a/packages/react-ui/components/MiniModal/__stories__/MiniModal.stories.tsx b/packages/react-ui/components/MiniModal/__stories__/MiniModal.stories.tsx deleted file mode 100644 index c940cfa981b..00000000000 --- a/packages/react-ui/components/MiniModal/__stories__/MiniModal.stories.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import React from 'react'; -import { TrashCanIcon64Regular } from '@skbkontur/icons/TrashCanIcon64Regular'; -import { TechPhoneSmartIcon64Regular } from '@skbkontur/icons/TechPhoneSmartIcon64Regular'; - -import { MiniModal } from '../MiniModal'; -import { Button } from '../../Button'; -import { Modal } from '../../Modal'; -import { Meta, Story } from '../../../typings/stories'; -import { ThemeContext } from '../../../lib/theming/ThemeContext'; -import { THEME_2022 } from '../../../lib/theming/themes/Theme2022'; -import { ThemeFactory } from '../../../lib/theming/ThemeFactory'; - -export default { - title: 'MiniModal', - parameters: { creevey: { captureElement: '[data-tid="modal-content"]' } }, -} as Meta; - -export const Simple = () => ( - - Title - - - - -); - -export const MobileFullset: Story = () => ( - - {(theme) => ( - - - }>Title mobile - Lorem ipsum dolor sit amet, consectetur adipisicing elit. Earum, officia? - - - - - - - - - )} - -); -MobileFullset.parameters = { - viewport: { defaultViewport: 'iphone' }, - creevey: { captureElement: null }, -}; - -export const Description = () => ( - - Title - Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore, voluptatibus? - - - - -); - -export const TwoButtons = () => ( - - Title - - - - - -); - -export const Column = () => ( - - Title - - - - - -); - -export const ThreeButtons = () => ( - - Title - - - - - - -); - -export const Indent = () => ( - - Title - - - - - - - -); - -export const Icon = () => ( - - }>Title - - - - -); - -export const Custom = () => ( - - Delete? - - - - - -); diff --git a/packages/react-ui/components/Modal/__stories__/Modal.stories.tsx b/packages/react-ui/components/Modal/__stories__/Modal.stories.tsx deleted file mode 100644 index 36c1576fbd8..00000000000 --- a/packages/react-ui/components/Modal/__stories__/Modal.stories.tsx +++ /dev/null @@ -1,941 +0,0 @@ -// TODO: Rewrite stories and enable rule (in process of functional refactoring). -/* eslint-disable react/no-unstable-nested-components */ -import React, { useState, useContext } from 'react'; -import BorderAllIcon from '@skbkontur/react-icons/BorderAll'; - -import { ThemeFactory } from '../../../lib/theming/ThemeFactory'; -import { CreeveyTests, Story } from '../../../typings/stories'; -import { Modal } from '../Modal'; -import { Button } from '../../Button'; -import { Input } from '../../Input'; -import { Toggle } from '../../Toggle'; -import { delay } from '../../../lib/utils'; -import { ThemeContext } from '../../../lib/theming/ThemeContext'; -import { ResponsiveLayout } from '../../ResponsiveLayout'; - -const basicFontStyle = { - fontSize: '14px', - lineHeight: '20px', - margin: '0', -}; - -interface ModalWithScrollableContentState { - opened: boolean; - panel: boolean; -} -class ModalWithScrollableContent extends React.Component { - public state: ModalWithScrollableContentState = { - opened: false, - panel: false, - }; - - public render() { - return ( -
- {this.state.opened && this.renderModal()} - -

- On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized - by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble - that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, - which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to - distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able - to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances - and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to - be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle - of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse - pains. -

-

- On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized - by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble - that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, - which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to - distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able - to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances - and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to - be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle - of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse - pains. -

-
- ); - } - - public renderModal() { - return ( - - Title - -

Use rxjs operators with react hooks

- -
- this.setState(({ panel }: ModalWithScrollableContentState) => ({ panel: !panel }))} - />{' '} - Panel {this.state.panel ? 'enabled' : 'disabled'} -
-
- - - -
- ); - } - - public open = () => { - this.setState({ opened: true }); - }; - - public close = () => { - this.setState({ opened: false }); - }; -} - -interface ModalWithIconInputState { - opened: boolean; -} -class ModalWithIconInput extends React.Component { - public state: ModalWithIconInputState = { - opened: false, - }; - - public renderModal() { - return ( - - - } rightIcon={} /> - } rightIcon={} /> - } rightIcon={} /> - - - } rightIcon={} /> - } rightIcon={} /> - } rightIcon={} /> - - - } rightIcon={} /> - } rightIcon={} /> - } rightIcon={} /> - - - ); - } - - public render() { - return ( -
- {this.state.opened && this.renderModal()} - -
- ); - } - - public open = () => { - this.setState({ opened: true }); - }; - - public close = () => { - this.setState({ opened: false }); - }; -} - -class ModalOverAnotherModal extends React.Component { - public state = { - firstModalOpened: false, - secondModalOpened: false, - }; - - public renderModal(name: string, width: number) { - return ( - - Модалка #{name === 'firstModalOpened' ? '1' : '2'} - - {name === 'firstModalOpened' && ( - - )} - - - ); - } - - public render() { - const { firstModalOpened, secondModalOpened } = this.state; - - return ( -
- {firstModalOpened && this.renderModal('firstModalOpened', 500)} - {secondModalOpened && this.renderModal('secondModalOpened', 300)} - -
- ); - } - - public close(name: string) { - this.setState({ [name]: false }); - } -} - -const ModalWithFooterPanel = () => { - const [isOpen, setIsOpen] = useState(false); - - return ( -
- {isOpen && ( - setIsOpen(false)}> - Адрес места осуществления предпринимательской деятельности - - - - - - - - - )} - -
- ); -}; - -export const ModalWithFooterPanelStory: Story = () => ; -ModalWithFooterPanelStory.storyName = 'Modal with footer panel'; - -ModalWithFooterPanelStory.parameters = { - creevey: { - tests: { - async 'open modal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Button"]:nth-of-type(1)' })) - .perform(); - await delay(100); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); - }, - }, - }, -}; - -interface ModalWithoutFooterPanelState { - opened: boolean; -} -class ModalWithoutFooterPanel extends React.Component { - public state: ModalWithoutFooterPanelState = { - opened: false, - }; - - public renderModal() { - return ( - - Исправление ошибок - -

- Исправить ошибки можно у нас в сервисе. Для этого загрузите документы для редактирования. Также можно - посмотреть ошибки, исправить их в учетной программе и импортировать заново. -

-
- - - - -
- ); - } - - public render() { - return ( -
- {this.state.opened && this.renderModal()} - -
- ); - } - - public open = () => { - this.setState({ opened: true }); - }; - - public close = () => { - this.setState({ opened: false }); - }; -} - -interface ModalWithoutFooterState { - opened: boolean; -} -class ModalWithoutFooter extends React.Component { - public state: ModalWithoutFooterState = { - opened: false, - }; - - public renderModal() { - return ( - - Воспользуйтесь другим браузером - -

- Некоторые функции не работают в вашем браузере. Чтобы все работало, установите один из этих браузеров: - Firefox, Opera, Chrome. -

-
-
- ); - } - - public render() { - return ( -
- {this.state.opened && this.renderModal()} - -
- ); - } - - public open = () => { - this.setState({ opened: true }); - }; - - public close = () => { - this.setState({ opened: false }); - }; -} - -interface ModalInnerState { - bigHeight: boolean; -} -class ModalInner extends React.Component { - public state: ModalInnerState = { - bigHeight: false, - }; - - public render() { - return ( - - ); - } -} - -interface ModalWithVariableHeightState { - opened: boolean; - panel: boolean; -} -class ModalWithVariableHeight extends React.Component { - public state: ModalWithVariableHeightState = { - opened: false, - panel: false, - }; - - public render() { - return ( -
- {this.state.opened && ( - - Title - -

Use rxjs operators with react hooks

- - {this.props.children} - -
- this.setState(({ panel }: ModalWithVariableHeightState) => ({ panel: !panel }))} - />{' '} - Panel {this.state.panel ? 'enabled' : 'disabled'} -
-
- - - -
- )} - -
- ); - } - - public open = () => { - this.setState({ opened: true }); - }; - - public close = () => { - this.setState({ opened: false }); - }; -} - -class SmallModalOnTop extends React.Component { - public state = { - opened: false, - }; - - public renderModal() { - return ( - - Modal - - - - - ); - } - - public render() { - return ( -
- {this.state.opened && this.renderModal()} - -
- ); - } - - public open = () => { - this.setState({ opened: true }); - }; - - public close = () => { - this.setState({ opened: false }); - }; -} - -export default { title: 'Modal' }; - -export const WithScrollableParentContent = () => ; -WithScrollableParentContent.storyName = 'With scrollable parent content'; -WithScrollableParentContent.parameters = { creevey: { skip: true } }; - -export const WithIconInput: Story = () => ; - -WithIconInput.parameters = { - creevey: { - tests: { - async 'open modal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); - }, - }, - }, -}; - -export const ModalOverAnotherModalStory: Story = () => ; -ModalOverAnotherModalStory.storyName = 'Modal over another modal'; - -ModalOverAnotherModalStory.parameters = { - creevey: { - tests: { - async 'open first modal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-first-modal"]' })) - .perform(); - await delay(200); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open first modal'); - }, - async 'open second modal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-first-modal"]' })) - .perform(); - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-tid~="open-second-modal"]' })) - .perform(); - await delay(100); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open second modal'); - }, - }, - }, -}; - -export const DisabledModal = () => ( - - Disabled - Content of disabled body - -); -DisabledModal.storyName = 'Disabled modal'; -DisabledModal.parameters = { creevey: { skip: true } }; - -export const ModalWithoutFooterPanelStory: Story = () => ; -ModalWithoutFooterPanelStory.storyName = 'Modal without footer panel'; - -ModalWithoutFooterPanelStory.parameters = { - creevey: { - tests: { - async 'open modal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await delay(200); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); - }, - }, - }, -}; - -export const ModalWithoutFooterStory: Story = () => ; -ModalWithoutFooterStory.storyName = 'Modal without footer'; - -ModalWithoutFooterStory.parameters = { - creevey: { - tests: { - async 'open modal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); - }, - }, - }, -}; - -export const ModalWithoutHeader = () => ( - - -
- Некоторые функции не работают в вашем браузере. Чтобы все работало, установите один из этих браузеров: Firefox, - divpera, Chrome. -
-
-
-); -ModalWithoutHeader.storyName = 'Modal without header'; -ModalWithoutHeader.parameters = { creevey: { captureElement: null } }; - -export const ModalMobileView: Story = () => { - const theme = useContext(ThemeContext); - - return ( - - - Воспользуйтесь другим браузером - - Некоторые функции не работают в вашем браузере. Чтобы все работало, установите один из этих браузеров: - Firefox, Opera, Chrome. - - - - - - - ); -}; -ModalMobileView.storyName = 'Modal mobile view'; -ModalMobileView.parameters = { - viewport: { defaultViewport: 'iphone' }, - creevey: { - tests: { - async idle() { - await this.expect(await this.browser.takeScreenshot()).to.matchImage('idle'); - }, - }, - }, -}; - -export const ModalWithVariableHeightOfContent: Story = () => ( - - - -); -ModalWithVariableHeightOfContent.storyName = 'Modal with variable height of content'; - -ModalWithVariableHeightOfContent.parameters = { - creevey: { - tests: { - async 'open modal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await delay(100); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); - }, - async 'toggle content height'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '#modal-inner [data-comp-name~="Toggle"]' })) - .pause(500) - .perform(); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('toggle content height'); - }, - }, - }, -}; - -const TopMiddleBottomModalTests: CreeveyTests = { - async top() { - await this.expect(await this.browser.takeScreenshot()).to.matchImage('top'); - }, - async middle() { - await this.browser.executeScript(function () { - const modalContainer = window.document.querySelector('[data-tid="modal-container"]') as HTMLElement; - const modalContent = window.document.querySelector('[data-tid="modal-content"]') as HTMLElement; - - modalContainer.scrollTop = modalContent.offsetHeight / 2; - }); - await delay(100); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('middle'); - }, - async bottom() { - await this.browser.executeScript(function () { - const modalContainer = window.document.querySelector('[data-tid="modal-container"]') as HTMLElement; - const modalContent = window.document.querySelector('[data-tid="modal-content"]') as HTMLElement; - - modalContainer.scrollTop = modalContent.offsetHeight; - }); - await delay(100); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('bottom'); - }, -}; - -export const ModalWithoutStickyElements: Story = () => ( - - Header - - {new Array(200).fill('Use rxjs operators with react hooks.').map((item, index) => ( -

{item}

- ))} -
- Footer -
-); -ModalWithoutStickyElements.storyName = 'Modal without sticky elements'; - -ModalWithoutStickyElements.parameters = { creevey: { tests: TopMiddleBottomModalTests } }; - -export const WithAlignTop = () => ( - - -

Use rxjs operators with react hooks.

-
-
-); -WithAlignTop.storyName = 'With alignTop'; -WithAlignTop.parameters = { creevey: { captureElement: null } }; - -export const SmallModalOnTheTop: Story = () => ; -SmallModalOnTheTop.storyName = 'Small modal on the Top'; - -SmallModalOnTheTop.parameters = { - creevey: { - tests: { - async 'open modal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await delay(100); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); - }, - async 'close by click on the cross'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-tid="modal-close"]' })) - .perform(); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('close by click on the cross'); - }, - async "doesn't close by click on the content"() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-tid="modal-content-button"]' })) - .perform(); - await this.expect(await this.browser.takeScreenshot()).to.matchImage("doesn't close by click on the content"); - }, - async 'closes by click on the background'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-tid="modal-container"]' })) - .perform(); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('closes by click on the background'); - }, - }, - }, -}; - -export const ModalWithVeryLongHeaderWithoutSpaces = () => ( - - VeryLongAndStrangeHeaderWithoutMeaningAndSpaces - -); -ModalWithVeryLongHeaderWithoutSpaces.storyName = 'Modal with veryLongHeaderWithoutSpaces'; -ModalWithVeryLongHeaderWithoutSpaces.parameters = { creevey: { captureElement: null } }; - -export const ModalWithHeaderFromOtherComponent = () => { - const Header = () => Header ; - return ( - -
- asdjhaklsdkajs -
- ); -}; -ModalWithHeaderFromOtherComponent.storyName = 'Modal with Header from other Component'; -ModalWithHeaderFromOtherComponent.parameters = { creevey: { skip: true } }; - -export const ModalBodyWithoutPadding = () => ( - - {(theme) => { - return ( - - -
-

Loooooooong content content content

-

Loooooooong content content content

-

Loooooooong content content content

-

Loooooooong content content content

-
-
-
- ); - }} -
-); -ModalBodyWithoutPadding.storyName = 'Modal with no-padding'; -ModalBodyWithoutPadding.parameters = { creevey: { captureElement: null } }; - -export const AlignCenterAndNoClose = () => ( - - -
Header
-
- -
-

Loooooooong content content content

-
-
-
-); -AlignCenterAndNoClose.parameters = { creevey: { captureElement: null } }; - -const Header = () => Header; -const Body = () => ( - - {new Array(200).fill('Use rxjs operators with react hooks.').map((item, index) => ( -

{item}

- ))} -
-); -const Footer = () => ( - - Footer - -); - -export const ModalWithChildrenFromOtherComponent = () => ( - -
- -
- -); - -ModalWithChildrenFromOtherComponent.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: ['top', 'middle'] }, - }, - tests: TopMiddleBottomModalTests, - }, -}; - -export const MobileModal: Story = () => { - const [isOpen, setOpen] = useState(false); - const [showThirdButton, setShowThird] = useState(false); - - const modal = ( - - {({ isMobile }) => { - return ( - setOpen(false)}> - Это какой-то заголовок заголовок - -

- {new Array(80).fill( - 'ст ст ст ст ст ст ст ст ст ст ст ст ст ст ст ст ст ст ст ст ст ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст', - 0, - 80, - )} -

-
- - - - {showThirdButton && ( - - )} - -
- ); - }} -
- ); - - const render = ( -
- - {isOpen && modal} -
- ); - - return render; -}; -MobileModal.storyName = 'Mobile modal'; -MobileModal.parameters = { - viewport: { - defaultViewport: 'iphonePlus', - }, - creevey: { - tests: { - async top() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await delay(200); - - await this.expect(await this.browser.takeScreenshot()).to.matchImage('top'); - }, - async middle() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await delay(200); - - await this.browser.executeScript(function () { - const modalContent = window.document.querySelector('.focus-lock-container') as HTMLElement; - const modalBody = window.document.querySelector('[data-comp-name~="ModalBody"] ') as HTMLElement; - - modalContent.scrollTop = modalBody.offsetHeight / 2; - }); - await delay(100); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('middle'); - }, - async bottom() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await delay(200); - - await this.browser.executeScript(function () { - const modalContent = window.document.querySelector('.focus-lock-container') as HTMLElement; - const modalBody = window.document.querySelector('[data-comp-name~="ModalBody"] ') as HTMLElement; - - modalContent.scrollTop = modalBody.offsetHeight; - }); - - await delay(100); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('bottom'); - }, - }, - }, -}; diff --git a/packages/react-ui/components/Paging/__stories__/Paging.stories.tsx b/packages/react-ui/components/Paging/__stories__/Paging.stories.tsx deleted file mode 100644 index 79399e38c51..00000000000 --- a/packages/react-ui/components/Paging/__stories__/Paging.stories.tsx +++ /dev/null @@ -1,330 +0,0 @@ -import React from 'react'; -import { action } from '@storybook/addon-actions'; -import { ComponentStory } from '@storybook/react'; - -import { Meta, Story } from '../../../typings/stories'; -import { ItemComponentProps, Paging } from '../Paging'; -import { delay, emptyHandler } from '../../../lib/utils'; -import { PagingProps } from '..'; - -const lorem = `Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolores -dignissimos labore expedita. Sapiente beatae eveniet sit, similique, -sunt corrupti deserunt ab eius nobis suscipit praesentium labore. -Distinctio hic asperiores consequatur?`; - -interface GoToAbsensePageState { - activePage: number; -} -class GoToAbsensePage extends React.Component { - public state: GoToAbsensePageState = { - activePage: 3, - }; - - public render() { - const pagesCount = this._getPagesCount(this.state.activePage); - return ( -
-
- -
-
- ); - } - - private _getPagesCount = (activePage: number) => { - return activePage <= 4 ? 7 : 5; - }; - - private _handlePageChange = (pageNumber: number) => { - const pagesCount = this._getPagesCount(pageNumber); - const activePage = Math.min(pageNumber, pagesCount); - this.setState({ activePage }); - }; -} - -interface PagingWithStateProps extends Partial { - pagesCount: number; -} -interface PagingWithStateState { - activePage: number; -} -class PagingWithState extends React.Component { - public state: PagingWithStateState = { - activePage: 1, - }; - - public render() { - return ( -
- -
- ); - } - - private _handlePageChange = (pageNumber: number) => { - this.setState({ activePage: pageNumber }, () => action('page cahnged')(this.state.activePage)); - }; -} - -const getPageFromHash = () => +document.location.hash.slice(1); - -const CustomComponent = ({ children, pageNumber, active, ...rest }: ItemComponentProps) => { - if (Paging.isForward(pageNumber)) { - return ( - - {children} - - ); - } - - return ( -
- {children} - - ); -}; - -interface PagingWithCustomComponentProps { - pagesCount: number; -} -interface PagingWithCustomComponentState { - activePage: number; -} -class PagingWithCustomComponent extends React.Component { - public state: PagingWithCustomComponentState = { - activePage: 1, - }; - - public componentDidMount() { - document.location.hash = '#1'; - window.addEventListener('hashchange', this._handleHashChange); - } - - public componentWillUnmount() { - document.location.hash = ''; - window.removeEventListener('hashchange', this._handleHashChange); - } - - public render() { - return ( -
- -
- ); - } - - public _handlePageChange = (pageNumber: number) => { - document.location.hash = '#' + pageNumber; - }; - - public _handleHashChange = () => { - this.setState({ activePage: getPageFromHash() }); - }; -} - -export default { - title: 'Paging', - decorators: [ - (Story: () => JSX.Element) => ( -
- -
- ), - ], -} as Meta; - -export const GoToAbsensePageStory: Story = () => ; -GoToAbsensePageStory.storyName = 'GoToAbsensePage'; - -GoToAbsensePageStory.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'hover' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { - in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], - tests: ['hover', 'Move to page by Ender'], - }, - flaky: { - in: ['firefox2022', 'firefox2022Dark'], - tests: ['Move focus right', 'Move to page by Ender'], - }, - }, - tests: { - async plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('plain'); - }, - async hover() { - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` }), - }) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('hover'); - }, - async 'change page by number'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('change page by number'); - }, - async 'change page by forwardLink'() { - // NOTE Firefox bug if click send right after click from previous test it results as double click - await delay(500); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: `[data-tid='Paging__forwardLink']` })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('change page by forwardLink'); - }, - async focused() { - // NOTE Firefox bug if click send right after click from previous test it results as double click - await delay(500); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('focused'); - }, - async 'Move focus right'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` })) - .pause(100) - .sendKeys(this.keys.ARROW_RIGHT) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('Move focus right'); - }, - async 'Move to page by Ender'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` })) - .pause(100) - .sendKeys(this.keys.ARROW_RIGHT) - .pause(100) - .sendKeys(this.keys.ENTER) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('Move to page by Ender'); - }, - }, - }, -}; - -export const SimpleSamples = () => ( - <> - - - - - -); -SimpleSamples.storyName = 'SimpleSamples'; -SimpleSamples.parameters = { creevey: { skip: true } }; - -export const PagingWithCustomComponentStory = () => ; -PagingWithCustomComponentStory.storyName = 'PagingWithCustomComponent'; -PagingWithCustomComponentStory.parameters = { creevey: { skip: true } }; - -export const PagingWithGlobalListener = () => ; -PagingWithGlobalListener.storyName = 'Paging with global listener'; -PagingWithGlobalListener.parameters = { creevey: { skip: true } }; - -const Template: ComponentStory = (args) => { - return ; -}; - -export const WithLongItems = Template.bind({}); -WithLongItems.args = { - activePage: 753000, - pagesCount: 7530050, -}; - -export const DisabledPaging = () => { - return ; -}; -DisabledPaging.parameters = { - creevey: { - skip: { in: /^(?!\b(chrome|chromeDark|chrome2022|chrome2022Dark)\b)/ }, - }, -}; - -export const PagingDisabledForwardLink = () => { - return ; -}; -PagingDisabledForwardLink.parameters = { - creevey: { - skip: { in: /^(?!\b(chrome|chromeDark|chrome2022|chrome2022Dark)\b)/ }, - }, -}; - -export const PlaygroundStory = () => ; -PlaygroundStory.storyName = 'Playground'; -PlaygroundStory.parameters = { creevey: { skip: true } }; - -interface PlaygroundState { - useGlobalListener: boolean; -} -class Playground extends React.Component { - public state: PlaygroundState = { - useGlobalListener: true, - }; - - public render() { - return ( -
-

-

{lorem}

-

- -

-

- - - - - -

-

- -

- -
- ); - } - - private handleChangeGlobalListener = (event: React.ChangeEvent) => { - this.setState({ useGlobalListener: event.target.checked }); - }; - - private log = (event: React.KeyboardEvent) => { - action(event.type)(event.key); - }; -} diff --git a/packages/react-ui/components/PasswordInput/__stories__/PasswordInput.stories.tsx b/packages/react-ui/components/PasswordInput/__stories__/PasswordInput.stories.tsx deleted file mode 100644 index 7f41ff4e785..00000000000 --- a/packages/react-ui/components/PasswordInput/__stories__/PasswordInput.stories.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import React from 'react'; - -import { Story } from '../../../typings/stories'; -import { PasswordInput } from '../PasswordInput'; -import { Nullable } from '../../../typings/utility-types'; - -interface ComponentProps { - capsLockEnabled?: boolean; -} -interface ComponentState { - value: string; -} -class Component extends React.Component { - public state: ComponentState = { - value: '', - }; - - private _passwordInput: Nullable; - - public componentDidMount() { - if (this.props.capsLockEnabled) { - this.setState({ value: 'test' }); - if (this._passwordInput) { - this._passwordInput.setState({ capsLockEnabled: true }); - } - } - } - - public render() { - return ( -
- { - this._passwordInput = ref; - }} - value={this.state.value} - onValueChange={this._handleChange} - /> -
- ); - } - - private _handleChange = (value: string) => { - this.setState({ value }); - }; -} - -export default { title: 'PasswordInput' }; - -export const Plain: Story = () => ; -Plain.parameters = { - creevey: { - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['With visible password'] }, - 'flickering screenshot': { in: ['chrome2022'], tests: ['With typed password'] }, - }, - tests: { - async Plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); - }, - async 'With typed password'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[type="password"]' })) - .sendKeys('Test...') - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('With typed password'); - }, - async 'With visible password'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[type="password"]' })) - .sendKeys('Test...') - .click(this.browser.findElement({ css: '[data-tid="PasswordInputEyeIcon"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('With visible password'); - }, - }, - }, -}; -export const CapsLockLabel = () => ; -CapsLockLabel.storyName = 'CapsLock label'; diff --git a/packages/react-ui/components/Radio/__stories__/Radio.stories.tsx b/packages/react-ui/components/Radio/__stories__/Radio.stories.tsx deleted file mode 100644 index d5eaff7ae2a..00000000000 --- a/packages/react-ui/components/Radio/__stories__/Radio.stories.tsx +++ /dev/null @@ -1,128 +0,0 @@ -// TODO: Rewrite stories and enable rule (in process of functional refactoring). -/* eslint-disable react/no-unstable-nested-components */ -import React from 'react'; - -import { Meta, Story } from '../../../typings/stories'; -import { Gapped } from '../../Gapped'; -import { Radio } from '../Radio'; - -export default { - title: 'Radio', - parameters: { - creevey: { - skip: { - 'kind-skip-0': { stories: 'Playground' }, - }, - }, - }, -} as Meta; - -export const RadioWithDifferentStates = () => ( -
- - - - - - - - - - -
-); -RadioWithDifferentStates.storyName = 'Radio with different states'; -RadioWithDifferentStates.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['chromeFlat8px'] }, - }, - }, -}; - -export const Playground = () => { - class Comp extends React.Component { - public state = { - hovered: false, - checked: false, - active: false, - value: 'value', - }; - - public render() { - return ( -
-
- - - -
-
- ); - } - - private handleClick = () => { - this.setState({ checked: !this.state.checked }); - }; - } - - return ; -}; - -export const Highlighted: Story = () => { - return ( -
-
- -
-
- -
-
- -
-
- ); -}; - -Highlighted.parameters = { - creevey: { - skip: { - flaky: { in: /firefox/ }, - }, - tests: { - async plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('plain'); - }, - async tabPress() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'body' })) - .sendKeys(this.keys.TAB) - .pause(500) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); - }, - }, - }, -}; - -export const Size: Story = () => { - return ( -
- - - Size: small - - - Size: medium - - - Size: large - - -
- ); -}; diff --git a/packages/react-ui/components/RadioGroup/__stories__/RadioGroup.stories.tsx b/packages/react-ui/components/RadioGroup/__stories__/RadioGroup.stories.tsx deleted file mode 100644 index f46551cddf4..00000000000 --- a/packages/react-ui/components/RadioGroup/__stories__/RadioGroup.stories.tsx +++ /dev/null @@ -1,274 +0,0 @@ -import React from 'react'; - -import { Story } from '../../../typings/stories'; -import { RadioGroup } from '../RadioGroup'; -import { Radio } from '../../Radio'; -import { Gapped } from '../../Gapped'; -import { Button } from '../../Button'; -import { Nullable } from '../../../typings/utility-types'; -import { delay } from '../../../lib/utils'; -import { RadioGroupProps } from '..'; - -interface ComponentState { - value: string; -} -class Component extends React.Component> { - public state: ComponentState = { - value: '', - }; - - private _radioGroup: Nullable>; - - public render() { - return ( - - -
- - ref={(element) => (this._radioGroup = element)} - value={this.state.value} - onValueChange={this.handleValueChange} - {...this.props} - /> -
- -
- ); - } - - private handleValueChange = (value: string) => { - this.setState({ value }); - }; -} - -export default { title: 'RadioGroup' }; - -export const Vertical: Story = () => { - return ; -}; -Vertical.storyName = 'vertical'; - -Vertical.parameters = { - creevey: { - captureElement: '#RadioGroup-wrap', - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'hovered' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hovered', 'clicked'] }, - }, - tests: { - async plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('plain'); - }, - async hovered() { - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: '[data-comp-name~="RadioGroup"] > span > label' }), - }) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); - }, - async clicked() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="RadioGroup"] > span > label' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); - }, - async mouseLeave() { - // NOTE Firefox bug if click send right after click from previous test it results as double click - await delay(500); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="RadioGroup"] > span > label' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="JustButton"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('mouseLeave'); - }, - async tabPress() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="JustButton"]' })) - .sendKeys(this.keys.TAB) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); - }, - async arrow_down() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="JustButton"]' })) - .sendKeys(this.keys.TAB) - .pause(100) - .sendKeys(this.keys.DOWN) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('arrow_down'); - }, - }, - }, -}; - -export const Inline = () => ; -Inline.storyName = 'inline'; - -Inline.parameters = { - creevey: { - captureElement: '#RadioGroup-wrap', - }, -}; - -export const WithRenderItem = () => ( - items={['One', 'Two']} renderItem={(x) =>
Value: {x}
} /> -); -WithRenderItem.storyName = 'with renderItem'; -WithRenderItem.parameters = { creevey: { skip: true } }; - -export const MultipleGroups = () => ( -
- -
- -
- -
-); -MultipleGroups.storyName = 'multiple groups'; -MultipleGroups.parameters = { creevey: { skip: true } }; - -export const UncontrolledWithDefaultValue = () => ; -UncontrolledWithDefaultValue.storyName = 'uncontrolled with defaultValue'; -UncontrolledWithDefaultValue.parameters = { creevey: { skip: true } }; - -export const UncontrolledWithChildrenAndDefaultValue = () => ( - - - First element - Second element - Third element - - -); -UncontrolledWithChildrenAndDefaultValue.storyName = 'uncontrolled with children and default value'; -UncontrolledWithChildrenAndDefaultValue.parameters = { creevey: { skip: true } }; - -export const UncontrolledWithChildrenAndDifferentItemStates = () => ( - - - First element - - Second element - - - Warning element - - - Error element - - - -); -UncontrolledWithChildrenAndDifferentItemStates.storyName = 'uncontrolled with children and different item states'; -UncontrolledWithChildrenAndDifferentItemStates.parameters = { creevey: { skip: true } }; - -export const DisabledUncontrolledWithChildren = () => ( - - - First element - Second element - Third element - - -); -DisabledUncontrolledWithChildren.storyName = 'disabled uncontrolled with children'; -DisabledUncontrolledWithChildren.parameters = { creevey: { skip: true } }; - -export const ErrorUncontrolledWithChildren = () => ( - - - First element - Second element - Third element - - -); -ErrorUncontrolledWithChildren.storyName = 'error uncontrolled with children'; -ErrorUncontrolledWithChildren.parameters = { creevey: { skip: true } }; - -export const WarningUncontrolledWithChildren = () => ( - - - First element - Second element - Third element - - -); -WarningUncontrolledWithChildren.storyName = 'warning uncontrolled with children'; -WarningUncontrolledWithChildren.parameters = { creevey: { skip: true } }; - -export const NestedUncontrolledGroupsWithChildren = () => ( - - - First element - - Second element - - Third element - - - First element - Second element - - - First element - - Second element - - Third element - - - Third element - - - Fourth element - Fifth element - - -); -NestedUncontrolledGroupsWithChildren.storyName = 'nested uncontrolled groups with children'; -NestedUncontrolledGroupsWithChildren.parameters = { creevey: { skip: true } }; - -export const Disabled = () => ( - - - First element - Second element - Third element - - -); -Disabled.storyName = 'disabled'; diff --git a/packages/react-ui/components/ScrollContainer/__stories__/ScrollContainer.stories.tsx b/packages/react-ui/components/ScrollContainer/__stories__/ScrollContainer.stories.tsx deleted file mode 100644 index 2befba5f1ac..00000000000 --- a/packages/react-ui/components/ScrollContainer/__stories__/ScrollContainer.stories.tsx +++ /dev/null @@ -1,731 +0,0 @@ -// TODO: Rewrite stories and enable rule (in process of functional refactoring). -/* eslint-disable react/no-unstable-nested-components */ -import React, { CSSProperties, useState } from 'react'; - -import { - ScrollContainer, - ScrollContainerScrollState, - ScrollContainerScrollStateX, - ScrollContainerScrollStateY, -} from '../ScrollContainer'; -import { Story } from '../../../typings/stories'; -import { Gapped } from '../../Gapped'; -import { ThemeContext } from '../../../lib/theming/ThemeContext'; -import { delay } from '../../../lib/utils'; - -function getItems(count: number) { - const items = []; - for (let i = 0; i < count; i += 1) { - items.push(i); - } - return items; -} - -const wrapperStyle = { - height: '200px', - width: '100px', - border: '1px solid #000', -}; - -const DynamicContent: React.FC< - React.PropsWithChildren<{ - state: ScrollContainerScrollStateY | ScrollContainerScrollStateX; - scroll: (percentage: number) => void; - add: () => void; - remove: () => void; - onChangeScrollYState?: (x: ScrollContainerScrollStateY) => void; - onChangeScrollXState?: (x: ScrollContainerScrollStateX) => void; - }> -> = ({ children, state, scroll, add, remove, onChangeScrollXState, onChangeScrollYState }) => { - return ( - -
- -
- - {children} - -
-
scroll state: {state}
-
-
- - - - - -
- ); -}; - -export default { title: 'ScrollContainer' }; - -export const WithLargeContentHeight = () => { - return ( -
- - {getItems(1000).map((i) => ( -
{i}
- ))} -
-
- ); -}; -WithLargeContentHeight.storyName = 'with large content height'; - -export const WithHorizontalScroll = () => { - return ( -
- - {getItems(100).map((i) => ( -
- {i} -
- ))} -
-
- ); -}; - -interface WrapperState { - scrollState: ScrollContainerScrollState; -} -export const WithScrollState = () => { - class Wrapper extends React.Component { - public state: WrapperState = { scrollState: 'top' as ScrollContainerScrollState }; - - public render() { - const commonBlocksStyles: CSSProperties = { - padding: '5px 10px', - position: 'relative', - transition: 'box-shadow 0.2s', - zIndex: 1, - }; - - const headerStyles: CSSProperties = { - boxShadow: this.state.scrollState !== 'top' ? '0 5px 10px rgba(0, 0, 0, 0.2)' : 'none', - ...commonBlocksStyles, - }; - - const footerStyles: CSSProperties = { - boxShadow: this.state.scrollState !== 'bottom' ? 'rgba(0, 0, 0, 0.2) 0px -5px 10px' : 'none', - background: '#f1f1f1', - ...commonBlocksStyles, - }; - - const footerDarkStyles: CSSProperties = { - boxShadow: this.state.scrollState !== 'bottom' ? 'rgba(0, 0, 0, 0.2) 0px -5px 10px' : 'none', - background: '#1f1f1f', - ...commonBlocksStyles, - }; - - const scrollContainerWrapperStyles: CSSProperties = { - ...wrapperStyle, - border: 'none', - padding: '0px 5px', - boxSizing: 'border-box', - }; - - return ( - - {(theme) => { - return ( -
-
header
-
- - {getItems(20).map((i) => ( -
{i}
- ))} -
-
-
- footer -
-
- ); - }} -
- ); - } - - private handleScrollStateChange = (scrollState: ScrollContainerScrollState) => { - this.setState({ scrollState }); - }; - } - - return ; -}; -WithScrollState.storyName = 'with scroll state'; - -export const WithDynamicContent: Story = () => { - const [items, setItems] = React.useState(4); - const [state, setState] = React.useState('top'); - const add = () => setItems(items + 1); - const remove = () => setItems(items > 0 ? items - 1 : 0); - const scroll = (percentage: number) => { - const scrollContainer = window.document.querySelector('[data-tid~="ScrollContainer__inner"]'); - if (scrollContainer) { - scrollContainer.scrollTop = (scrollContainer.scrollHeight - scrollContainer.clientHeight) * (percentage / 100); - } - }; - return ( - - {getItems(items).map((i) => ( -
- {i} -
- ))} -
- ); -}; -WithDynamicContent.parameters = { - creevey: { - captureElement: '#test-container', - tests: { - async changeContent() { - const idle = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#add' })) - .perform(); - const addContent = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scroll50' })) - .perform(); - const scroll50 = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scroll100' })) - .perform(); - const scroll100 = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#remove' })) - .perform(); - const removeContent = await this.takeScreenshot(); - - await this.expect({ idle, addContent, scroll50, scroll100, removeContent }).to.matchImages(); - }, - }, - }, -}; - -export const WithOnlyCustomHorizontalScroll: Story = () => { - const [state, setState] = React.useState('left'); - const [items, setItems] = React.useState(4); - - const add = () => setItems(items + 1); - const remove = () => setItems(items > 0 ? items - 1 : 0); - - const scroll = (percentage: number) => { - const scrollContainer = window.document.querySelector('[data-tid~="ScrollContainer__inner"]'); - if (scrollContainer) { - scrollContainer.scrollLeft = (scrollContainer.scrollWidth - scrollContainer.clientWidth) * (percentage / 100); - } - }; - - return ( - - {getItems(items).map((i) => ( -
- {i} -
- ))} -
- ); -}; - -WithOnlyCustomHorizontalScroll.storyName = 'with only custom horizontal scroll'; -WithOnlyCustomHorizontalScroll.parameters = { - creevey: { - captureElement: '#test-container', - tests: { - async moveScroll() { - const idle = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scroll50' })) - .perform(); - const scroll50 = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scroll100' })) - .perform(); - const scroll100 = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scroll0' })) - .perform(); - const scroll0 = await this.takeScreenshot(); - - await this.expect({ idle, scroll50, scroll100, scroll0 }).to.matchImages(); - }, - - async changeContent() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#add' })) - .perform(); - const addContent = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scroll50' })) - .perform(); - const scroll50 = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scroll100' })) - .perform(); - const scroll100 = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scroll0' })) - .perform(); - const scroll0 = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#remove' })) - .perform(); - const removeContent = await this.takeScreenshot(); - - await this.expect({ addContent, scroll50, scroll100, scroll0, removeContent }).to.matchImages(); - }, - }, - }, -}; - -export const WithScrollTo: Story = () => { - const refScrollContainer = React.useRef(null); - - const countItems = 8; - - const scrollTo = () => refScrollContainer.current?.scrollTo(document.getElementById(`-${countItems - 1}`)); - const scrollToTop = () => refScrollContainer.current?.scrollToTop(); - const scrollToLeft = () => refScrollContainer.current?.scrollToLeft(); - const scrollToRight = () => refScrollContainer.current?.scrollToRight(); - const scrollToBottom = () => refScrollContainer.current?.scrollToBottom(); - - return ( - -
- - {getItems(countItems).map((i) => ( -
-
- {-i} -
-
- {i} -
-
- ))} -
-
- - - - - - - -
- ); -}; - -WithScrollTo.parameters = { - creevey: { - captureElement: '#test-container', - tests: { - async scrollTo() { - const idle = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scrollTo' })) - .perform(); - const scrollTo = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scrollToTop' })) - .perform(); - const scrollToTop = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scrollToLeft' })) - .perform(); - const scrollToLeft = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scrollToBottom' })) - .perform(); - const scrollToBottom = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scrollToRight' })) - .perform(); - const scrollToRight = await this.takeScreenshot(); - - await this.expect({ - idle, - scrollTo, - scrollToTop, - scrollToBottom, - scrollToLeft, - scrollToRight, - }).to.matchImages(); - }, - }, - }, -}; - -export const OffsetY: Story = () => ( -
- - {Array(30) - .fill(null) - .map((_, i) => ( -
{i}
- ))} -
-
-); -OffsetY.parameters = { - creevey: { skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }, -}; - -export const OffsetX = () => ( -
- -
- {Array(10) - .fill(null) - .map((_, i) => ( -
- {i} -
- ))} -
-
-
-); -OffsetX.parameters = { - creevey: { skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }, -}; - -export const OffsetYAndX: Story = () => ( -
- -
- {Array(30) - .fill(null) - .map((_, i) => ( -
- {i} -
- ))} -
-
-
-); -OffsetYAndX.parameters = { - creevey: { skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }, -}; - -export const HideScrollBar: Story = () => ( -
- -
- {Array(30) - .fill(null) - .map((_, i) => ( -
- {i} -
- ))} -
-
-
-); -HideScrollBar.parameters = { - creevey: { - skip: { 'themes dont affect logic': { in: /^(?!\b(firefox|chrome)\b)/ } }, - tests: { - async hideScroll() { - const beforeScroll = await this.takeScreenshot(); - await this.browser.executeScript(function () { - const scrollContainer = window.document.querySelector('[data-tid~="ScrollContainer__inner"]'); - if (scrollContainer) { - scrollContainer.scrollTop = 500; - } - }); - this.browser - .actions({ - bridge: true, - }) - .move({ origin: this.browser.findElement({ css: 'body' }) }); - await delay(200); - const duringScroll = await this.takeScreenshot(); - await delay(3000); - const afterScroll = await this.takeScreenshot(); - await this.expect({ beforeScroll, duringScroll, afterScroll }).to.matchImages(); - }, - }, - }, -}; - -export const ScrollBarVisibleAfterTogglingDisabled: Story = () => { - const [isDisabled, setIsDisabled] = useState(false); - - return ( -
- -
- {Array(30) - .fill(null) - .map((_, i) => ( -
- {i} -
- ))} -
-
- -
- ); -}; - -ScrollBarVisibleAfterTogglingDisabled.storyName = 'scroll bar visible after toggling disabled'; -ScrollBarVisibleAfterTogglingDisabled.parameters = { - creevey: { - skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, - tests: { - async toggleDisabled() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="disable-button"]' })) - .click(this.browser.findElement({ css: '[data-tid="disable-button"]' })) - .perform(); - - await this.expect(await this.takeScreenshot()).to.matchImage('toggleDisabled'); - }, - }, - }, -}; - -export const ShowScrollBarOnScroll: Story = () => ( -
- -
- {Array(30) - .fill(null) - .map((_, i) => ( -
- {i} -
- ))} -
-
-
-); -ShowScrollBarOnScroll.parameters = { - creevey: { - skip: { 'themes dont affect logic': { in: /^(?!\b(firefox|chrome)\b)/ } }, - tests: { - async hideScroll() { - const beforeScroll = await this.takeScreenshot(); - await this.browser.executeScript(function () { - const scrollContainer = window.document.querySelector('[data-tid~="ScrollContainer__inner"]'); - if (scrollContainer) { - scrollContainer.scrollTop = 500; - } - }); - this.browser - .actions({ - bridge: true, - }) - .move({ origin: this.browser.findElement({ css: 'body' }) }); - await delay(200); - const duringScroll = await this.takeScreenshot(); - await delay(3000); - const afterScroll = await this.takeScreenshot(); - await this.expect({ beforeScroll, duringScroll, afterScroll }).to.matchImages(); - }, - }, - }, -}; - -export const ShowScrollBarOnHover: Story = () => ( -
- -
- {Array(30) - .fill(null) - .map((_, i) => ( -
- {i} -
- ))} -
-
-
-); -ShowScrollBarOnHover.parameters = { - creevey: { - skip: { 'hover works only in firefox': { in: /^(?!\b(firefox)\b)/ } }, - tests: { - async hideScroll() { - this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: '[data-tid~="ScrollContainer__root"]' }), - }) - .perform(); - await delay(500); - const hovered = await this.takeScreenshot(); - this.browser - .actions({ - bridge: true, - }) - .move({ x: 1000, y: 700 }) - .perform(); - await delay(3000); - const withoutHover = await this.takeScreenshot(); - await this.expect({ hovered, withoutHover }).to.matchImages(); - }, - }, - }, -}; - -export const NeverShowScrollBar: Story = () => ( -
- -
- {Array(30) - .fill(null) - .map((_, i) => ( -
- {i} -
- ))} -
-
-
-); -NeverShowScrollBar.parameters = { - creevey: { - skip: { 'themes dont affect logic': { in: /^(?!\b(firefox|chrome)\b)/ } }, - }, -}; diff --git a/packages/react-ui/components/Select/__stories__/Select.stories.tsx b/packages/react-ui/components/Select/__stories__/Select.stories.tsx deleted file mode 100644 index 1e9ae10a64f..00000000000 --- a/packages/react-ui/components/Select/__stories__/Select.stories.tsx +++ /dev/null @@ -1,845 +0,0 @@ -// TODO: Rewrite stories and enable rule (in process of functional refactoring). -/* eslint-disable react/no-unstable-nested-components */ -import React, { useState } from 'react'; -import AddIcon from '@skbkontur/react-icons/Add'; -import { action } from '@storybook/addon-actions'; -import { CSFStory } from 'creevey'; - -import { Meta, Story, CreeveyTests } from '../../../typings/stories'; -import { isKeyEnter } from '../../../lib/events/keyboard/identifiers'; -import { Button } from '../../Button'; -import { Select, SelectProps } from '../Select'; -import { Gapped } from '../../Gapped'; -import { ResponsiveLayout } from '../../ResponsiveLayout'; -import { delay } from '../../../lib/utils'; -import { MenuItem } from '../../MenuItem'; - -const mobileDecorator = (Story: () => JSX.Element) => { - return ( -
- -
- ); -}; -interface SelectWrapperValue { - label: string; - value: number; -} -interface SelectWrapperState { - value: SelectWrapperValue; -} -class SelectWrapper extends React.Component { - public state: SelectWrapperState = { - value: { label: 'One', value: 1 }, - }; - - public render() { - return ( -
- - items={[ - { label: 'One', value: 1 }, - { label: 'Two', value: 2 }, - { label: 'Three', value: 3 }, - ]} - value={this.state.value} - onValueChange={(value) => this.setState({ value })} - renderItem={(x) => x.label} - renderValue={(x) => { - if (x) { - return x.label; - } - }} - /> -
- ); - } -} - -interface ItemsWithCommentsState { - value: number; -} -type ItemWithComments = [number, string, React.ReactNode?]; -class ItemsWithComments extends React.Component { - private static items: ItemWithComments[] = [ - [1, 'ООО Эльбрус', '8387666415 - 113445852'], - [2, 'ИП Иванов Петр', '583662338391'], - [3, 'ЗАО Текстильщики'], - ]; - - public state: ItemsWithCommentsState = { - value: ItemsWithComments.items[0][0], - }; - - public render() { - return ( -
- - width={200} - value={this.state.value} - items={ItemsWithComments.items} - onValueChange={(value) => this.setState({ value })} - /> -
- ); - } -} - -type SelectWithNullStateValue = number | null; -interface SelectWithNullState { - value: SelectWithNullStateValue; -} -class SelectWithNull extends React.Component { - public state: SelectWithNullState = { - value: null, - }; - - public render() { - return ( -
-
- value: {JSON.stringify(this.state.value)} -
- - items={[[null, 'Any'], Select.SEP, [1, 'First'], [2, 'Second'], [3, 'Third']]} - value={this.state.value} - onValueChange={(value) => this.setState({ value })} - /> -
- ); - } -} - -const clickedTest: CreeveyTests = { - async clicked() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); - }, -}; - -const selectTests: CreeveyTests = { - async idle() { - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('idle'); - }, - ...clickedTest, - async 'MenuItem hover'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' }), - }) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('MenuItem hover'); - }, - async 'selected item'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('selected item'); - }, -}; - -export const Simple: Story = () => ( -
- - )} - setShow({ ...show, showSecond: !show.showSecond })}>With big count of items - {show.showSecond && } - console.log(layout)} /> - - ); -}; -MobileSimple.title = 'Mobile stories'; -MobileSimple.parameters = { - viewport: { - defaultViewport: 'iphone', - }, - creevey: { skip: true }, -}; -MobileSimple.decorators = [ - (Story: () => JSX.Element) => ( -
-
- -
-
- ), -]; - -export const MobileWithLongItem: Story = () => { - const longItem = 'Two '.repeat(50); - - return ( -
- -
- ); -}; - -MobileWithLongItem.parameters = { - viewport: { - defaultViewport: 'iphone', - }, -}; - -export const MobileWithSearch: Story = () => ( - -); -MobileWithTitle.parameters = { - viewport: { - defaultViewport: 'iphone', - }, - creevey: { - tests: clickedTest, - }, -}; -MobileWithTitle.decorators = [mobileDecorator as () => JSX.Element]; - -export const MobileWithTitleAndSearch: Story = () => ( - -); -MobileWithoutTitleAndSearch.parameters = { - viewport: { - defaultViewport: 'iphone', - }, - creevey: { - tests: clickedTest, - }, -}; -MobileWithoutTitleAndSearch.decorators = [mobileDecorator as () => JSX.Element]; - -export const Disabled: CSFStory = () => ( - <> - - -); - -Disabled.storyName = 'disabled'; - -export const ComplexValues = () => ; -ComplexValues.storyName = 'Complex values'; -ComplexValues.parameters = { creevey: { skip: true } }; - -export const ItemsWithCommentsStory = () => ; -ItemsWithCommentsStory.storyName = 'Items with comments'; -ItemsWithCommentsStory.parameters = { creevey: { skip: true } }; - -export const WithNull = () => ; -WithNull.storyName = 'With null'; -WithNull.parameters = { creevey: { skip: true } }; - -export const UseLink: Story = () => } use="link" items={['one', 'two', 'three']} />; -UseLinkWithIcon.storyName = 'use link with icon'; - -UseLinkWithIcon.parameters = { - creevey: { - captureElement: '.dropdown-test-container', - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'MenuItem hover' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['MenuItem hover'] }, - }, - tests: selectTests, - }, -}; - -export const WithTextOverflow: Story = () => -
- -
- ); - } - - private refSelect: React.RefObject(); - - private handleClick = () => { - if (this.selectElem) { - this.selectElem.focus(); - } - }; - } - - return ; -}; -ExternalFocus.storyName = 'external focus'; -ExternalFocus.parameters = { creevey: { skip: true } }; - -export const UsingOnKeyDown: Story = () => { - class Sample extends React.Component { - public state = { - opened: false, - text: 'wait...', - }; - private button: Button | null = null; - public render() { - return ( -
- (selectElem = ref)} search width={width} items={['one', 'two', 'three']} /> -
- ); -}; -WithSearchAndVariousWidth.storyName = 'with search'; - -WithSearchAndVariousWidth.parameters = { - creevey: { - captureElement: '#test-element', - skip: { - flaky: { in: ['chrome2022', 'chrome2022Dark'] }, - }, - tests: { - async search() { - const root = await this.browser.findElement({ css: '[data-tid="root"]' }); - const select = await this.browser.findElement({ css: '[data-comp-name~="Select"]' }); - - await this.browser - .actions({ - bridge: true, - }) - .click(select) - .pause(500) - .perform(); - - const plainSearch = await root.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.ARROW_DOWN) - .pause(500) - .perform(); - - const pressKeyDown = await root.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Input"]' })) - .sendKeys('test') - .pause(500) - .perform(); - - const fullFieldSearch = await root.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(select) - .click(select) - .pause(500) - .perform(); - - const emptySearch = await root.takeScreenshot(); - - await this.expect({ plainSearch, pressKeyDown, fullFieldSearch, emptySearch }).to.matchImages(); - }, - - async 'and various width'() { - const root = await this.browser.findElement({ css: '[data-tid="root"]' }); - - await this.browser - .actions({ bridge: true }) - .click(await this.browser.findElement({ css: '[data-tid="w100px"]' })) - .pause(500) - .perform(); - - const w100px = await root.takeScreenshot(); - - await this.browser - .actions({ bridge: true }) - .click(await this.browser.findElement({ css: '[data-tid="w300px"]' })) - .pause(500) - .perform(); - - const w300px = await root.takeScreenshot(); - - await this.browser - .actions({ bridge: true }) - .click(await this.browser.findElement({ css: '[data-tid="w100prc"]' })) - .pause(500) - .perform(); - - const w100prc = await root.takeScreenshot(); - - await this.expect({ w100px, w300px, w100prc }).to.matchImages(); - }, - }, - }, -}; - -export const WithMenuAlignAndVariousWidth: Story = () => { - const widths: Array['width']> = [ - undefined, - '80px', - '120px', - '80%', - '120%', - 'calc(100% + 40px)', - ]; - const row: Array>> = [ - { menuAlign: 'right' }, - { menuAlign: 'right', disablePortal: true }, - { menuAlign: 'left' }, - { menuAlign: 'left', disablePortal: true }, - ]; - const renderSelect = (width: SelectProps['width'], props: Partial>) => ( - - - -
- ); -}; -WithManualPosition.storyName = 'with manual position'; -WithManualPosition.parameters = { - creevey: { - skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } }, - tests: { - async 'opened top with portal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened top with portal'); - }, - async 'opened bottom with portal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom with portal'); - }, - async 'opened top without portal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="portal"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened top without portal'); - }, - async 'opened bottom without portal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="portal"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom without portal'); - }, - }, - }, -}; - -export const Size: Story = () => { - const items = ['one', two, 'three']; - let small: Select | null = null; - let medium: Select | null = null; - let large: Select | null = null; - const handleClick = () => { - if (small) { - small.open(); - } - if (medium) { - medium.open(); - } - if (large) { - large.open(); - } - }; - return ( -
- - - { - medium = element; - }} - /> - {' '} - -
- , - )} -
-); -TooltipsWithoutWrapperAroundInlineBlockWith50Width.storyName = - 'Tooltips without wrapper around inline-block with 50% width'; - -TooltipsWithoutWrapperAroundInlineBlockWith50Width.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark', 'firefox8px'] }, - }, - tests: { - async hover() { - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: 'textarea' }), - }) - .perform(); - await delay(1500); - await this.expect(await this.takeScreenshot()).to.matchImage('hover'); - }, - }, - }, -}; - -export const OpenedTooltipWithoutWrapper = () => ( - - Without wrapper - -); -OpenedTooltipWithoutWrapper.storyName = 'Opened tooltip without wrapper'; - -export const TooltipWithExternalDynamicContent: Story = () => ( - -); -TooltipWithExternalDynamicContent.storyName = 'Tooltip with external dynamic content'; - -TooltipWithExternalDynamicContent.parameters = { - creevey: { - tests: { - async '01 - plain'() { - await delay(1000); - await this.expect(await this.takeScreenshot()).to.matchImage('01 - plain'); - }, - async '02 - changes top position if does not fit'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#Container-0 button' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('02 - changes top position if does not fit'); - }, - async '03 - does not change position back on shrink'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#Container-0 button' })) - .pause(100) - .click(this.browser.findElement({ css: '#Container-0 button' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('03 - does not change position back on shrink'); - }, - async '04 - does not change top position if fits'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#Container-1 button' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('04 - does not change top position if fits'); - }, - async '05 - does not change position on shrink'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#Container-1 button' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#Container-1 button' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('05 - does not change position on shrink'); - }, - async '06 - changes left position if does not fit'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#Container-2 button' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('06 - changes left position if does not fit'); - }, - async '07 - does not change position back on shrink'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#Container-2 button' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#Container-2 button' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('07 - does not change position back on shrink'); - }, - async '08 - does not change bottom position if fits'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#Container-3 button' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('08 - does not change bottom position if fits'); - }, - async '09 - does not change position on shrink'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#Container-3 button' })) - .pause(100) - .click(this.browser.findElement({ css: '#Container-3 button' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('09 - does not change position on shrink'); - }, - async '10 - does not change bottom position if does not fit'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#Container-4 button' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage( - '10 - does not change bottom position if does not fit', - ); - }, - async '11 - does not change position on shrink'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#Container-4 button' })) - .pause(100) - .click(this.browser.findElement({ css: '#Container-4 button' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('11 - does not change position on shrink'); - }, - }, - }, -}; - -export const TooltipWithInternalDynamicContent = () => ( - -); -TooltipWithInternalDynamicContent.storyName = 'Tooltip with internal dynamic content'; -TooltipWithInternalDynamicContent.parameters = { creevey: { skip: true } }; - -export const TooltipWithTriggerClick = () => ; -TooltipWithTriggerClick.storyName = 'Tooltip with trigger=click'; -TooltipWithTriggerClick.parameters = { creevey: { skip: true } }; - -export const TooltipWithDynamicAnchor = () => ; -TooltipWithDynamicAnchor.storyName = 'Tooltip with dynamic anchor'; -TooltipWithDynamicAnchor.parameters = { creevey: { skip: true } }; - -export const MultipleTooltipsWithUseWrapperFalse = () => ; -MultipleTooltipsWithUseWrapperFalse.storyName = 'Multiple tooltips with useWrapper=false'; -MultipleTooltipsWithUseWrapperFalse.parameters = { creevey: { skip: true } }; - -export const TooltipWithInputAndSwitchableContent: Story = () => ; -TooltipWithInputAndSwitchableContent.storyName = 'Tooltip with Input and switchable content'; - -TooltipWithInputAndSwitchableContent.parameters = { - creevey: { - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { - in: ['firefox8px', 'firefoxFlat8px', 'firefox', 'firefoxDark'], - tests: ['focus and types', 'clear input'], - }, - }, - tests: { - async 'focus and types'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'input' })) - .sendKeys('Hi') - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('focus and types'); - }, - async 'clear input'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'input' })) - .sendKeys('Hi') - .sendKeys(this.keys.BACK_SPACE, this.keys.BACK_SPACE) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('clear input'); - }, - }, - }, -}; - -export const DynamicTriggersStory: Story = () => ; -DynamicTriggersStory.storyName = 'dynamic triggers'; - -DynamicTriggersStory.parameters = { - creevey: { - captureElement: '[data-comp-name~="TestTooltip"]', - skip: { - 'story-skip-0': { - in: ['ie11', 'ie118px', 'ie11Dark'], - tests: ['hover - mouseEnter', 'hover&focus - mouseEnter'], - }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { - in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], - tests: [ - 'hover - mouseEnter', - 'click - click anchor', - 'focus - focus', - 'hover&focus - mouseEnter', - 'hover&focus - focus', - ], - }, - }, - tests: { - async 'without trigger'() { - await delay(1000); - await this.expect(await this.takeScreenshot()).to.matchImage('without trigger'); - }, - async 'hover - mouseEnter'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#hover' })) - .move({ - origin: this.browser.findElement({ css: '[type="button"]' }), - }) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('hover - mouseEnter'); - }, - async 'hover - mouseLeave'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#hover' })) - .move({ - origin: this.browser.findElement({ css: '[type="button"]' }), - }) - .pause(500) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: 'body' }), - }) - .pause(500) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('hover - mouseLeave'); - }, - async 'click - click anchor'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#click' })) - .click(this.browser.findElement({ css: '[type="button"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('click - click anchor'); - }, - async 'click - click outside'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#click' })) - .click(this.browser.findElement({ css: '[type="button"]' })) - .click(this.browser.findElement({ css: 'body' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('click - click outside'); - }, - async 'focus - focus'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#focus' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[type="button"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('focus - focus'); - }, - async 'focus - blur'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#focus' })) - .click(this.browser.findElement({ css: '[type="button"]' })) - .click(this.browser.findElement({ css: 'body' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('focus - blur'); - }, - async opened() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#opened' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened'); - }, - async closed() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#opened' })) - .click(this.browser.findElement({ css: '#closed' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('closed'); - }, - async 'hover&focus - mouseEnter'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#hover_focus' })) - .move({ - origin: this.browser.findElement({ css: '[type="button"]' }), - }) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('hover&focus - mouseEnter'); - }, - async 'hover&focus - mouseLeave'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#hover_focus' })) - .move({ - origin: this.browser.findElement({ css: '[type="button"]' }), - }) - .move({ - origin: this.browser.findElement({ css: 'body' }), - }) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('hover&focus - mouseLeave'); - }, - async 'hover&focus - focus'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#hover_focus' })) - .click(this.browser.findElement({ css: '[type="button"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('hover&focus - focus'); - }, - async 'hover&focus - focus - mouseLeave'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#hover_focus' })) - .click(this.browser.findElement({ css: '[type="button"]' })) - .move({ - origin: this.browser.findElement({ css: 'body' }), - }) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('hover&focus - focus - mouseLeave'); - }, - async 'hover&focus - blur'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#hover_focus' })) - .click(this.browser.findElement({ css: '[type="button"]' })) - .pause(100) - .sendKeys(this.keys.TAB) - .click(this.browser.findElement({ css: 'body' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('hover&focus - blur'); - }, - }, - }, -}; - -export const RenderInFirstAvailablePosition: Story = () => ( -
- -
-); -RenderInFirstAvailablePosition.storyName = 'Render in first available position'; - -RenderInFirstAvailablePosition.parameters = { - creevey: { - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { - in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], - tests: ['render in available position', 'relocate on new available position'], - }, - }, - tests: { - async 'render in available position'() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[type="button"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('render in available position'); - }, - async 'relocate on new available position'() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[type="button"]' })) - .perform(); - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[type="button"]' })) - .perform(); - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[type="button"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('relocate on new available position'); - }, - }, - }, -}; - -interface DynamicContentTooltipState { - content: React.ReactNode; - opened: boolean; -} - -class DynamicContentTooltip extends React.Component { - public state: DynamicContentTooltipState = { - content: SMALL_CONTENT, - opened: false, - }; - - public render() { - return ( - - - - ); - } - - private buttonClickHandler = () => { - const getContent = (state: DynamicContentTooltipState) => { - if (state.opened) { - return state.content; - } else if (state.content === SMALL_CONTENT) { - return LARGE_CONTENT; - } - - return SMALL_CONTENT; - }; - - this.setState((state: DynamicContentTooltipState) => ({ - content: getContent(state), - opened: !state.opened, - })); - }; - - private tooltipContentGetter = () => { - return this.state.content; - }; -} - -class TooltipWithInput extends React.Component { - public state = { show: false }; - public render() { - return ( -
- - this.setState({ show: Boolean(v) })} /> - -
- ); - } - - public renderContent = () => { - if (this.state.show) { - return {'Content'}; - } - return null; - }; -} - -interface MyCustomTooltipState { - state: TooltipTrigger; -} - -class MyCustomTooltip extends React.Component { - public state: MyCustomTooltipState = { - state: 'hover', - }; - - public render() { - const tooltipProps: Partial = - this.state.state === 'hover' - ? { trigger: 'hover' } - : { - trigger: 'opened', - onCloseRequest: () => this.setState({ state: 'hover' }), - }; - - return ( - 'hola'} {...tooltipProps}> - - - ); - } -} - -class ManualTooltip extends React.Component { - public state: MyCustomTooltipState = { - state: 'opened', - }; - - public render() { - const tooltipProps: Partial = { - trigger: this.state.state, - closeButton: false, - }; - - return ( - 'hola'} {...tooltipProps}> - - - ); - } -} - -const SMALL_CONTENT = Sample text; -function getSmallContent() { - return SMALL_CONTENT; -} -const LARGE_CONTENT = ( - - Sample text, sample text, sample text, sample text, sample text -
- Sample text, sample text, sample text, sample text, sample text -
- Sample text, sample text, sample text, sample text, sample text -
- Sample text, sample text, sample text, sample text, sample text -
- Sample text, sample text, sample text, sample text, sample text -
- Sample text, sample text, sample text, sample text, sample text -
-); - -interface HasPopupPositionProps { - pos: PopupPositionsType; -} -interface HasDynamicContentState { - content: React.ReactNode; -} -class ExternalDynamicContentTooltip extends React.Component { - public state: HasDynamicContentState = { - content: SMALL_CONTENT, - }; - - public render() { - return ( - - - - ); - } - - private buttonClickHandler = () => { - this.setState({ - content: this.state.content === SMALL_CONTENT ? LARGE_CONTENT : SMALL_CONTENT, - }); - }; - - private tooltipContentGetter = () => { - return this.state.content; - }; -} - -class TooltipWithDynamicContent extends React.Component { - public state: HasDynamicContentState = { - content: SMALL_CONTENT, - }; - - public render() { - return ( -
-
- -
-
{this.state.content}
-
- ); - } - private buttonClickHandler = () => { - this.setState({ - content: this.state.content === SMALL_CONTENT ? LARGE_CONTENT : SMALL_CONTENT, - }); - }; -} - -class InternalDynamicContentTooltip extends React.Component { - public render() { - return ( - - Tooltip anchor - - ); - } - - private tooltipContentGetter = () => { - return ; - }; -} - -class DynamicAnchor extends React.Component { - public state = { - isFirst: true, - }; - public render() { - return this.state.isFirst ? ( - First anchor - ) : ( -
- Second anchor -
- ); - } - private onClickHandler = () => { - this.setState({ isFirst: !this.state.isFirst }); - }; -} - -const DYNAMIC_TOOLTIP_POSITIONS: PopupPositionsType[] = [ - 'top left', - 'top left', - 'left middle', - 'bottom left', - 'bottom left', -]; - -interface DynamicContentStoryProps { - TooltipComponentClass: typeof ExternalDynamicContentTooltip | typeof InternalDynamicContentTooltip; -} -const DynamicContentStory = (props: DynamicContentStoryProps) => { - const { TooltipComponentClass } = props; - return ( -
- {DYNAMIC_TOOLTIP_POSITIONS.map((position, index) => { - return ( -
- -
- ); - })} -
- ); -}; - -function DynamicAnchorTooltip() { - return ( -
- - - -
- ); -} - -class TooltipWithClickTrigger extends React.Component { - public render() { - return ( -
- - Click me - -
- ); - } - private outerTooltipContentGetter = () => { - return ( - - Item 1 - Item 2 - - Click me for more... - - - ); - }; - private innerTooltipContentGetter = () => { - return ( - - More: - Item 3 - Item 4 - - ); - }; -} - -function MultipleTooltips() { - return ( -
- - - - - Poor anchor - - - - -
- ); -} - -interface DynamicTriggersState { - trigger?: TooltipTrigger; -} - -class DynamicTriggers extends React.Component { - public state: DynamicTriggersState = {}; - - public render() { - const triggers: TooltipTrigger[] = ['hover', 'click', 'focus', 'opened', 'closed', 'hoverAnchor', 'hover&focus']; - return ( -
-
- {triggers.map((trigger) => ( - - ))} -
- - - -
- ); - } - - private setTrigger = (trigger: TooltipTrigger) => { - this.setState({ - trigger, - }); - }; -} - -class TestTooltipForManual extends React.Component { - private tooltip: Tooltip | null = null; - public state = { onOpenCalledTimes: 0, onCloseCalledTimes: 0 }; - - render() { - return ( -
- -
onOpen called {this.state.onOpenCalledTimes} times
-
onClose called {this.state.onCloseCalledTimes} times
-
- - - - - - 'Opened by Show()'} - trigger="manual" - pos="bottom left" - ref={(element) => { - this.tooltip = element; - }} - onOpen={() => { - this.setState({ onOpenCalledTimes: this.state.onOpenCalledTimes + 1 }); - }} - onClose={() => { - this.setState({ onCloseCalledTimes: this.state.onCloseCalledTimes + 1 }); - }} - > - - -
- ); - } - - handleClickOnShow() { - if (this.tooltip) { - this.tooltip.show(); - } - } - handleClickOnHide() { - if (this.tooltip) { - this.tooltip.hide(); - } - } -} - -export const TooltipWithManualControl: Story = () => ; -TooltipWithManualControl.storyName = 'manual control'; - -TooltipWithManualControl.parameters = { - creevey: { - tests: { - async 'call show'() { - const btns = await this.browser.findElements({ css: '[type="button"]' }); - await this.browser - .actions({ - bridge: true, - }) - .click(btns[0]) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('call show'); - }, - async 'call hide after show'() { - const btns = await this.browser.findElements({ css: '[type="button"]' }); - await this.browser - .actions({ - bridge: true, - }) - .click(btns[0]) - .click(btns[1]) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('call hide after show'); - }, - }, - }, -}; - -export const TooltipWithIconFromPackage = () => ( - - - -); -TooltipWithIconFromPackage.storyName = 'tooltip with icon'; - -const FunctionalChild = () => { - return
FunctionalChild
; -}; -export const TooltipWithFunctionalChild = () => ( - - - -); -TooltipWithFunctionalChild.storyName = 'tooltip with functional child'; - -const anchorStyle: CSSProperties = { - left: 60, - position: 'absolute', - height: 55, - width: 55, - border: '1px solid #dfdede', -}; - -interface AnchorTooltipExampleState { - anchor: Nullable; -} -class AnchorTooltipExample extends React.Component { - public state: AnchorTooltipExampleState = { - anchor: null, - }; - - render() { - return ( - <> - {this.state.anchor ? ( - 'Hello React'} trigger="hover" /> - ) : null} -
-
this.setState({ anchor: event.target as HTMLElement })} - onMouseLeave={() => this.setState({ anchor: null })} - /> -
this.setState({ anchor: event.target as HTMLElement })} - onMouseLeave={() => this.setState({ anchor: null })} - /> -
- - ); - } -} - -export const TooltipWithAnchor: Story = () => ; - -TooltipWithAnchor.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie11Dark', 'ie11Flat', 'ie118px', 'ie11Flat8px'] }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { - in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], - tests: ['hover by dynamic anchor'], - }, - }, - tests: { - async 'hover by dynamic anchor'() { - await this.browser - .actions({ - bridge: true, - }) - .move({ x: 0, y: 0 }) - .move({ origin: this.browser.findElement({ css: '[data-tid~="tooltip_anchor_1"]' }) }) - .perform(); - - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('hover by dynamic anchor'); - }, - }, - }, -}; -TooltipWithAnchor.storyName = 'Tooltip with anchor'; diff --git a/packages/react-ui/components/TooltipMenu/__stories__/TooltipMenu.creevey.stories.tsx b/packages/react-ui/components/TooltipMenu/__stories__/TooltipMenu.creevey.stories.tsx deleted file mode 100644 index 4babd296d7d..00000000000 --- a/packages/react-ui/components/TooltipMenu/__stories__/TooltipMenu.creevey.stories.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import React from 'react'; -import MenuIcon from '@skbkontur/react-icons/Menu'; -import LightbulbIcon from '@skbkontur/react-icons/Lightbulb'; - -import { delay } from '../../../lib/utils'; -import { CreeveyTests, Meta } from '../../../typings/stories'; -import { TooltipMenu } from '../TooltipMenu'; -import { MenuHeader } from '../../../components/MenuHeader'; -import { MenuItem } from '../../../components/MenuItem'; -import { PopupMenuDataTids } from '../../../internal/PopupMenu'; - -export default { - title: 'TooltipMenu/Functional tests', - decorators: [ - (Story: () => JSX.Element) => ( -
- -
- ), - ], - parameters: { - creevey: { - skip: { "themes don't affect logic": { in: /^(?!\bchrome\b)/ } }, - }, - }, -} as Meta; - -const textAlignmentTests: CreeveyTests = { - async opened() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: `[data-tid~="${PopupMenuDataTids.caption}"]` })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened'); - }, -}; - -export const WithItemsAndIcons = () => ( -
- - - - } - > - MenuHeader - }>MenuItem1 - }>MenuItem2 - MenuItem3 - -
-); -WithItemsAndIcons.parameters = { - creevey: { - tests: textAlignmentTests, - skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, - }, -}; - -export const WithItemsAndIconsWithoutTextAlignment = () => ( -
- - - - } - > - MenuHeader - }>MenuItem1 - }>MenuItem2 - MenuItem3 - -
-); -WithItemsAndIconsWithoutTextAlignment.parameters = { - creevey: { - tests: textAlignmentTests, - skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, - }, -}; diff --git a/packages/react-ui/components/TooltipMenu/__stories__/TooltipMenu.stories.tsx b/packages/react-ui/components/TooltipMenu/__stories__/TooltipMenu.stories.tsx deleted file mode 100644 index bbe2acb2692..00000000000 --- a/packages/react-ui/components/TooltipMenu/__stories__/TooltipMenu.stories.tsx +++ /dev/null @@ -1,241 +0,0 @@ -import React from 'react'; -import MenuIcon from '@skbkontur/react-icons/Menu'; -import LightbulbIcon from '@skbkontur/react-icons/Lightbulb'; - -import { delay } from '../../../lib/utils'; -import { Meta, Story } from '../../../typings/stories'; -import { MenuItem } from '../../MenuItem'; -import { MenuHeader } from '../../MenuHeader'; -import { MenuSeparator } from '../../MenuSeparator'; -import { TooltipMenu } from '../TooltipMenu'; -import { Button } from '../../Button'; - -export default { - title: 'TooltipMenu', - decorators: [ - (Story: () => JSX.Element) => ( -
- -
- ), - ], -} as Meta; - -export const SimpleExample: Story = () => ( - Открыть меню}> - Заголовок меню - - Раз - Два - Три - -); -SimpleExample.storyName = 'Simple example'; - -SimpleExample.parameters = { - creevey: { - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { - in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], - tests: ['clickAfterClickedOnCaption', 'clicked'], - }, - - 'story-skip-1': { in: /(?!\b(firefox)\b)/, tests: ['tabPress'] }, - }, - tests: { - async plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('plain'); - }, - async clickAfterClickedOnCaption() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="PopupMenu"]' })) - .click(this.browser.findElement({ css: '[data-comp-name~="PopupMenu"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('clickAfterClickedOnCaption'); - }, - async clicked() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="PopupMenu"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); - }, - async clickedOutside() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="PopupMenu"]' })) - .click(this.browser.findElement({ css: 'body' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('clickedOutside'); - }, - async tabPress() { - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .perform(); - - await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); - }, - async enterPress() { - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .sendKeys(this.keys.ENTER) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('enterPress'); - }, - async escapePress() { - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .sendKeys(this.keys.ENTER) - .sendKeys(this.keys.ESCAPE) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('escapePress'); - }, - }, - }, -}; - -export const MobileExampleHorizontalPaddings: Story = () => ( - Открыть меню}> - Заголовок меню - - Раз - Два - Три - -); - -MobileExampleHorizontalPaddings.parameters = { - viewport: { - defaultViewport: 'iphone', - }, - creevey: { - captureElement: null, - tests: { - async opened() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '#test-element' })) - .perform(); - await delay(200); - await this.browser - .actions({ bridge: true }) - .move({ origin: this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' }) }) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened'); - }, - }, - }, -}; - -export const ExampleWithWidthOfMenu = () => ( - Открыть меню} menuWidth={300}> - Заголовок меню - - Раз - Два - Три - -); -ExampleWithWidthOfMenu.storyName = 'Example with width of menu'; -ExampleWithWidthOfMenu.parameters = { creevey: { skip: true } }; - -export const ExampleWithMaximumHeightOfMenu = () => ( - Открыть меню} menuMaxHeight={150}> - Заголовок меню - - Раз - Два - Три - -); -ExampleWithMaximumHeightOfMenu.storyName = 'Example with maximum height of menu'; -ExampleWithMaximumHeightOfMenu.parameters = { creevey: { skip: true } }; - -export const CaptionAcceptsAnArbitraryElement = () => ( - - - - } - menuWidth="220px" - > - Раз - Два - Три - -); -CaptionAcceptsAnArbitraryElement.storyName = 'Caption accepts an arbitrary element'; -CaptionAcceptsAnArbitraryElement.parameters = { creevey: { skip: true } }; - -export const MenuInRightPositionOnly = () => ( - - - - } - menuWidth="160px" - positions={['right top', 'right middle', 'right bottom']} - > - Раз - Два - Три - -); -MenuInRightPositionOnly.storyName = 'Menu in right position only'; -MenuInRightPositionOnly.parameters = { creevey: { skip: true } }; - -export const MenuInTopPositionOnlyAlignRight = () => ( - - - - } - menuWidth="150px" - positions={['top right']} - > - Раз - Два - Три - -); -MenuInTopPositionOnlyAlignRight.storyName = 'Menu in top position only, align right'; -MenuInTopPositionOnlyAlignRight.parameters = { creevey: { skip: true } }; - -export const MenuWithoutAnimations = () => ( - Нет анимации}> - Анимация не пройдет - - Я не верю в мультики - -); -MenuWithoutAnimations.storyName = 'Menu without animations'; -MenuWithoutAnimations.parameters = { creevey: { skip: true } }; diff --git a/packages/react-ui/components/__stories__/baseline.stories.tsx b/packages/react-ui/components/__stories__/baseline.stories.tsx deleted file mode 100644 index 09ed50f49bc..00000000000 --- a/packages/react-ui/components/__stories__/baseline.stories.tsx +++ /dev/null @@ -1,310 +0,0 @@ -import React from 'react'; -import SpinnerIcon from '@skbkontur/react-icons/Spinner'; -import CrownIcon from '@skbkontur/react-icons/Crown'; - -import { Button } from '../Button'; -import { Link } from '../Link'; -import { Input } from '../Input'; -import { ComboBox } from '../ComboBox'; -import { Spinner } from '../Spinner'; -import { Checkbox } from '../Checkbox'; -import { Kebab } from '../Kebab'; -import { Radio } from '../Radio'; -import { Toggle } from '../Toggle'; -import { MenuItem } from '../MenuItem'; -import { Gapped } from '../Gapped'; -import { Group } from '../Group'; -import { ThemeContext } from '../../lib/theming/ThemeContext'; -import { ThemeFactory } from '../../lib/theming/ThemeFactory'; -import { SizeProp } from '../../lib/types/props'; - -export default { title: 'Baseline' }; - -export const ButtonAndText = () => ( -
- Simple text -
-); -ButtonAndText.storyName = 'Button and text'; - -export const MediumButtonAndText = () => ( -
- Simple text -
-); -MediumButtonAndText.storyName = 'Medium Button and text'; - -export const LargeButtonAndText = () => ( -
- Simple text -
-); -LargeButtonAndText.storyName = 'Large Button and text'; - -export const ButtonAndLink = () => ( -
- Ok -
-); -ButtonAndLink.storyName = 'Button and link'; - -export const InputAndText = () => ( -
- Plain text -
-); -InputAndText.storyName = 'Input and text'; - -export const ButtonWithoutContentInFlex = () => ( -
-
-); -ButtonWithoutContentInFlex.storyName = 'Button without content in flex-container'; -ButtonWithoutContentInFlex.parameters = { creevey: { skip: true } }; - -export const ButtonWithContentInFlex = () => ( -
- Plain text -
-); -ButtonWithContentInFlex.storyName = 'Button with content in flex-container'; -ButtonWithContentInFlex.parameters = { creevey: { skip: true } }; - -export const InputWithButton = () => ; -InputWithButton.storyName = 'Input with button'; -InputWithButton.parameters = { creevey: { skip: true } }; - -export const TextInputInputLikeText = () => ( -
- Text - - - Promise.resolve([])} - /> -
-); -TextInputInputLikeText.storyName = 'Text, Input, InputLikeText'; - -export const TextLargeInput = () => ( -
- Text - -
-); -TextLargeInput.storyName = 'Text, Large Input'; - -export const TextButtons = () => ( -
- Text - - -
-); -TextButtons.storyName = 'Text, Buttons'; - -export const TextLargeButton = () => ( -
- Text - -
-); -TextLargeButton.storyName = 'Text, Large Button'; - -export const TextSpinner = () => ( -
- Text - -
-); -TextSpinner.storyName = 'Text, Spinner'; - -export const IconSpinner = () => ( -
- - -
-); -IconSpinner.storyName = 'Icon, Spinner'; - -export const Checkboxes = () => ( -
- Lorem dolor a L1{' '} - L1.1elit. amet. -
- Lorem ipsum dolor Label 2 sit amet{' '} - sit. -
-); -Checkboxes.storyName = 'Checkbox'; - -const BaselineFont: React.FC<{ - fontFamily: string; - size: SizeProp; - bg: string; - width?: string; -}> = ({ fontFamily, size, width = '120px', bg }) => { - const content = size.charAt(0).toUpperCase(); - return ( -
- -
{fontFamily}
- - Ok - }>Ok - }> - Ok - - Tg - - - Ch - - - Ch - - - - Rd - - - - }>Menu - - - Menu - - - Promise.resolve([])} - size={size} - /> - - - - - -
-
- ); -}; - -const BaselineSize: React.FC<{ size: SizeProp; bg: string; width?: string }> = ({ size, bg, width }) => ( -
- - {['Arial', 'Lab Grotesque', 'Segoe UI', 'Times New Roman'].map((fontFamily, i) => ( - - ))} - -
-); - -export const DifferentFontsAndSizes = () => ( - -); -DifferentFontsAndSizes.storyName = 'Different fonts in small'; - -export const NewStoryDifferentFontsAndSizesThemeM = () => ; -NewStoryDifferentFontsAndSizesThemeM.storyName = 'Different fonts in medium'; - -class DifferentFontsAndSizesThemeM extends React.Component { - public render() { - return ( -
- - {(theme) => ( - - - - )} - -
- ); - } -} - -export const NewStoryDifferentFontsAndSizesThemeL = () => ; -NewStoryDifferentFontsAndSizesThemeL.storyName = 'Different fonts in large'; - -class DifferentFontsAndSizesThemeL extends React.Component { - public render() { - return ( -
- - {(theme) => ( - - - - )} - -
- ); - } -} - -class SimpleForm extends React.Component { - public state = { - isFormSubmitted: false, - value: '', - }; - - public render() { - return ( -
-
{ - e.preventDefault(); - this.setState({ isFormSubmitted: true }); - }} - > - this.setState({ value })} /> - -
- {this.state.isFormSubmitted && {this.state.value}} -
- ); - } -} diff --git a/packages/react-ui/internal/CloseButtonIcon/__stories__/CloseButtonIcon.stories.tsx b/packages/react-ui/internal/CloseButtonIcon/__stories__/CloseButtonIcon.stories.tsx deleted file mode 100644 index b123963d3a4..00000000000 --- a/packages/react-ui/internal/CloseButtonIcon/__stories__/CloseButtonIcon.stories.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import React from 'react'; -import { CreeveyTestFunction } from 'creevey/lib/types/types'; - -import { CloseButtonIcon, CloseButtonIconProps } from '../CloseButtonIcon'; -import { ComponentTable } from '../../ComponentTable'; -import { Gapped } from '../../../components/Gapped'; -import { Story } from '../../../typings/stories'; -import { Input } from '../../../components/Input'; - -export default { - title: 'CloseButtonIcon', - parameters: { - creevey: { skip: { 'only available in theme2022': { in: /^(?!\b.*2022.*\b)/ } } }, - }, -}; - -type CloseButtonIconState = Partial; - -const sizeStates: CloseButtonIconState[] = [{ size: 16 }, { size: 20 }, { size: 24 }, { size: 30 }]; - -const sideStates: CloseButtonIconState[] = [{ side: 16 }, { side: 20 }, { side: 24 }, { side: 30 }]; - -export const Side = () => ( - ({ props }))} - cols={sizeStates.map((props) => ({ props }))} - presetProps={{ style: { background: 'rgba(50, 255, 50, 0.2)' } }} - /> -); - -export const VerticalAlign = () => { - const idle: React.CSSProperties = {}; - const baseline: React.CSSProperties = { display: 'flex', alignItems: 'baseline' }; - const center: React.CSSProperties = { display: 'flex', alignItems: 'center' }; - return ( - - {Object.entries({ idle, baseline, center }).map(([name, style], index) => ( -
- {name} - - Text - - Text - - Text -
- ))} -
- ); -}; - -export const Tabbable: Story = () => { - return ( - -
- notTabbable - - - -
-
- tabbable - - - -
-
- ); -}; -const clickThenTAB: (args: { clickDataTid: string }) => CreeveyTestFunction = ({ clickDataTid }) => - async function () { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: `[data-tid="${clickDataTid}"] input` })) - .pause(500) - .perform(); - const firstFocus = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .pause(500) - .perform(); - const secondFocus = await this.takeScreenshot(); - - await this.expect({ firstFocus, secondFocus }).to.matchImages(); - }; -Tabbable.parameters = { - creevey: { - skip: { - 'do not pass on teamcity': { in: ['firefox2022', 'firefox2022Dark'] }, - }, - tests: { - notTabbable: clickThenTAB({ clickDataTid: 'notTabbable' }), - tabbable: clickThenTAB({ clickDataTid: 'tabbable' }), - }, - }, -}; diff --git a/packages/react-ui/internal/CustomComboBox/__stories__/ComboBoxView.stories.tsx b/packages/react-ui/internal/CustomComboBox/__stories__/ComboBoxView.stories.tsx deleted file mode 100644 index cdf2e174858..00000000000 --- a/packages/react-ui/internal/CustomComboBox/__stories__/ComboBoxView.stories.tsx +++ /dev/null @@ -1,231 +0,0 @@ -import React from 'react'; -import OkIcon from '@skbkontur/react-icons/'; - -import { Story } from '../../../typings/stories'; -import { ComboBoxView } from '../ComboBoxView'; -import { Gapped } from '../../../components/Gapped'; -import { Modal } from '../../../components/Modal'; -import { MenuItem } from '../../../components/MenuItem'; -import { MenuSeparator } from '../../../components/MenuSeparator'; -import { MenuHeader } from '../../../components/MenuHeader'; - -export default { title: 'ComboBoxView' }; - -export const InputLikeText: Story = () => ( - - - - - - -
- {' '} - hello -
-
- {' '} - hello -
-
- {' '} - hello -
- - - - -
- ComboBoxView с правой иконкой в - состоянии загрузки -
- -
-); -InputLikeText.storyName = 'input like text'; - -const FIREFOX_REGEXP = /.*firefox.*/i; - -InputLikeText.parameters = { - creevey: { - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { - in: FIREFOX_REGEXP, - tests: ['focused first element'], - }, - }, - tests: { - async plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('plain'); - }, - async 'focused first element'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('focused first element'); - }, - }, - }, -}; - -export const InputLikeTextWithPlaceholder = () => ( - - - -
- - Hello -
-
-); -InputLikeTextWithPlaceholder.storyName = 'input like text with placeholder'; - -export const Opened: Story = () => ( - - - - - - - - - - - - - - - -
- - - -
- 'Не найдено'} /> - - `Показано ${found} из ${total}`} - /> -
- null} /> - - Add {query}} - /> -
-); -Opened.storyName = 'opened'; -Opened.parameters = { - creevey: { - skip: { - flacky: { in: ['chrome2022Dark'] }, - }, - }, -}; - -export const WithItems = () => ( -
- -
-); -WithItems.storyName = 'with items'; - -export const InFlexModal = () => ( - - -
-
- -
-
-
-
-); -InFlexModal.storyName = 'in flex modal'; -InFlexModal.parameters = { creevey: { captureElement: null } }; - -function simpleRenderValue(value: { value: number; label: string }) { - return value.label; -} - -function complexRenderValue({ id, name }: { id: React.ReactNode; name: React.ReactNode }) { - return ( -
- {name} - {id} -
- ); -} - -export const WithCountItems = () => { - const separator = React.useMemo(() => , []); - const items = [ - { id: 1, name: 'one' }, - , - { id: 2, name: 'two' }, - , - { id: 3, name: 'tree' }, - Скоро конец, - { id: 4, name: 'four' }, - separator, - Конец, - ]; - - return ( -
- complexRenderValue(item as { id: number; name: string })} - renderTotalCount={(found, total) => `Показано ${found} из ${total}`} - /> -
- ); -}; - -WithCountItems.storyName = 'with total count'; diff --git a/packages/react-ui/internal/DropdownContainer/__stories__/DropdownContainer.stories.tsx b/packages/react-ui/internal/DropdownContainer/__stories__/DropdownContainer.stories.tsx deleted file mode 100644 index e6f5ccba202..00000000000 --- a/packages/react-ui/internal/DropdownContainer/__stories__/DropdownContainer.stories.tsx +++ /dev/null @@ -1,322 +0,0 @@ -import React from 'react'; - -import { Story } from '../../../typings/stories'; -import { MenuItem } from '../../../components/MenuItem'; -import { DropdownContainer, DropdownContainerProps } from '../DropdownContainer'; -import { Menu } from '../../Menu'; -import { Button } from '../../../components/Button'; -import { getRootNode, rootNode, TSetRootNode } from '../../../lib/rootNode'; -import { delay } from '../../../lib/utils'; - -export default { title: 'DropdownContainer' }; - -export const VariousAlignsPortalsItemsAndScrollsStory: Story = () => ; -VariousAlignsPortalsItemsAndScrollsStory.storyName = 'various aligns portals items and scrolls'; - -VariousAlignsPortalsItemsAndScrollsStory.parameters = { - creevey: { - captureElement: 'body', - tests: { - async 'short Items'() { - await delay(2000); - await this.expect(await this.takeScreenshot()).to.matchImage('short Items'); - }, - async 'short Items scroll'() { - await this.browser.executeScript(function () { - const innerScroll = window.document.querySelector('#inner-scroll') as HTMLElement; - innerScroll.scrollTop = innerScroll.scrollHeight; - innerScroll.scrollLeft = innerScroll.scrollWidth; - }); - await delay(1000); - - await this.expect(await this.browser.takeScreenshot()).to.matchImage('short Items scroll'); - }, - async 'long Items'() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '#buttons button' })) - .perform(); - await delay(2000); - - await this.expect(await this.browser.takeScreenshot()).to.matchImage('long Items'); - }, - async 'long Items scroll'() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '#buttons button' })) - .perform(); - await delay(2000); - await this.browser.executeScript(function () { - const innerScroll = window.document.querySelector('#inner-scroll') as HTMLElement; - innerScroll.scrollTop = innerScroll.scrollHeight; - innerScroll.scrollLeft = innerScroll.scrollWidth; - }); - await delay(2000); - - await this.expect(await this.browser.takeScreenshot()).to.matchImage('long Items scroll'); - }, - }, - }, -}; - -interface VariousAlignsPortalsItemsAndScrollsState { - shown: { [id: string]: boolean }; - long: boolean; -} -type Align = 'left' | 'right'; -class VariousAlignsPortalsItemsAndScrolls extends React.Component { - public aligns: Align[] = ['left', 'right']; - public portals = [false, true]; - public rows = ['top', 'middle', 'bottom']; - public cols = ['left', 'center', 'right']; - public dropdowns: { - [id: string]: DropdownWithToggle | null; - } = {}; - - public state: VariousAlignsPortalsItemsAndScrollsState = { - shown: {}, - long: false, - }; - - public componentDidMount(): void { - Object.keys(this.dropdowns).forEach((dropdown) => this.toggle(dropdown, true)); - } - - public get isAllShown() { - const { shown } = this.state; - const all = Object.keys(shown); - return all.length > 0 && all.every((id) => shown[id]); - } - - public toggle = (id: string, value: boolean) => { - this.setState((state: VariousAlignsPortalsItemsAndScrollsState) => ({ - shown: { - ...state.shown, - [id]: value, - }, - })); - }; - - public toggleAll = (value: boolean) => { - const { shown } = this.state; - Object.keys(shown).forEach((key) => { - this.toggle(key, value); - }); - }; - - public render() { - return ( - -
- {this.renderControls()} - - {this.renderDropdowns()} - -
-
- ); - } - - private renderControls = () => ( -
-
- -   - -
-
- ); - - private renderDropdowns = () => { - const { rows, cols, aligns, portals } = this; - const { long, shown } = this.state; - return ( - - {(row, col) => - aligns.map((align) => - portals.map((disablePortal) => { - const dropdownId = `${row}-${col}-${align}-${disablePortal}`; - return ( -
- this.toggle(dropdownId, value)} - dropdownProps={{ align, disablePortal }} - > - - - {`${row}/${col}/align-${align}/portal-${!disablePortal}; `.repeat(long ? 3 : 1)} - - - -   - {`${align}, portal: ${!disablePortal}`} -
- ); - }), - ) - } -
- ); - }; - - private createDropdownRef = (id: string) => (element: DropdownWithToggle | null) => { - if (element) { - this.dropdowns[id] = element; - } - }; -} - -interface ScrollableContainerProps { - id?: string; -} -class ScrollableContainer extends React.Component> { - public render() { - return ( -
- {this.props.children} -
- ); - } -} - -interface ScrollMakerProps { - xScroll: number; - yScroll: number; -} -class ScrollMaker extends React.Component> { - public static defaultProps = { - xScroll: 100, - yScroll: 100, - }; - - public render() { - const { xScroll, yScroll } = this.props; - return ( -
- {this.props.children} -
- ); - } -} - -interface GridProps { - rows: string[]; - cols: string[]; - children: (row: string, col: string) => React.ReactNode; -} -class Grid extends React.Component { - public static Row = class Row extends React.Component { - public render() { - return ( -
- {this.props.children} -
- ); - } - }; - - public static Cell = class Cell extends React.Component { - public render() { - return
{this.props.children}
; - } - }; - - public render() { - const { rows, cols } = this.props; - return ( -
- {rows.map((row) => ( - - {cols.map((col) => ( - {this.props.children(row, col)} - ))} - - ))} -
- ); - } -} - -interface DropdownWithToggleProps { - show: boolean; - onToggle: (value: boolean) => void; - dropdownProps: { - align: DropdownContainerProps['align']; - disablePortal: DropdownContainerProps['disablePortal']; - }; -} -@rootNode -class DropdownWithToggle extends React.Component> { - private setRootNode!: TSetRootNode; - - public render() { - const { show, onToggle, dropdownProps } = this.props; - return ( - - onToggle(e.target.checked)} - ref={this.setRootNode} - /> - {show && ( - - {this.props.children} - - )} - - ); - } - - private getParent = () => { - return getRootNode(this); - }; -} diff --git a/packages/react-ui/internal/FileUploaderControl/__stories__/FileUploaderFile.stories.tsx b/packages/react-ui/internal/FileUploaderControl/__stories__/FileUploaderFile.stories.tsx deleted file mode 100644 index f859cc476cc..00000000000 --- a/packages/react-ui/internal/FileUploaderControl/__stories__/FileUploaderFile.stories.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import React from 'react'; - -import { Story } from '../../../typings/stories'; -import { FileUploaderFile } from '../FileUploaderFile/FileUploaderFile'; -import { FileUploaderFileStatus } from '../fileUtils'; - -export default { - title: 'FileUploaderFile', - decorators: [ - (storyFn: () => JSX.Element) => { - return
{storyFn()}
; - }, - ], -}; - -export const FileUploaderFileWithValidationError: Story = () => { - return ( -
- Promise.resolve(''), - webkitRelativePath: '', - arrayBuffer: () => Promise.resolve(new ArrayBuffer(0)), - slice: () => new Blob(), - stream: () => new ReadableStream(), - }, - status: FileUploaderFileStatus.Error, - validationResult: { isValid: false, message: 'Валидация не прошла' }, - }} - size="small" - /> -
- ); -}; - -FileUploaderFileWithValidationError.parameters = { - creevey: { - tests: { - async hover() { - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: '[data-tid="FileUploader__fileName"]' }), - }) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('hover'); - }, - }, - skip: { - 'story-skip-0': { - in: /^(?!\b(chrome)\b)/, - }, - }, - }, -}; diff --git a/packages/react-ui/internal/HideBodyVerticalScroll/__stories__/HideBodyVerticalScroll.stories.tsx b/packages/react-ui/internal/HideBodyVerticalScroll/__stories__/HideBodyVerticalScroll.stories.tsx deleted file mode 100644 index 5477d745f99..00000000000 --- a/packages/react-ui/internal/HideBodyVerticalScroll/__stories__/HideBodyVerticalScroll.stories.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import React, { useEffect, useState } from 'react'; - -import { HideBodyVerticalScroll } from '../HideBodyVerticalScroll'; -import { CreeveyTests, Meta, Story } from '../../../typings/stories'; -import { delay } from '../../../lib/utils'; - -export default { - title: 'HideBodyVerticalScroll', - parameters: { - creevey: { skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }, - }, -} as Meta; - -const testScrollLockUnlock: CreeveyTests = { - async 'scroll, lock, unlock'() { - const toggle = async () => { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="toggle-lock"]' })) - .perform(); - await delay(1000); - }; - - await this.browser.executeScript(function () { - const scrollContainer = window.document.documentElement; - scrollContainer.scrollTop = scrollContainer.scrollHeight; - }); - const scrolled = await this.browser.takeScreenshot(); - - await toggle(); - const locked = await this.browser.takeScreenshot(); - - await toggle(); - const unlocked = await this.browser.takeScreenshot(); - - await this.expect({ scrolled, locked, unlocked }).to.matchImages(); - }, -}; - -const SampleLockScroll = () => { - const [locked, setLocked] = useState(false); - const toggle = () => setLocked((prev) => !prev); - const status = locked ? 'on page' : 'not mounted'; - - return ( -
-
- - HideBodyVerticalScroll: {status} - {locked && } -
-
- ); -}; - -export const Sample: Story = () => ( -
- -
{'s c r o l l . '.repeat(100)}
-
-); -Sample.parameters = { creevey: { tests: testScrollLockUnlock } }; - -const renderScrollableContent = () => ( -
- -
{'s c r o l l . '.repeat(1000)}
-
-); - -export const WithScrollableContent: Story = () => renderScrollableContent(); -WithScrollableContent.parameters = { creevey: { tests: testScrollLockUnlock } }; - -export const WithHTMLOverflowYScroll: Story = () => { - document.documentElement.style.overflowY = 'scroll'; - - useEffect(() => { - return () => { - document.documentElement.style.overflowY = ''; - }; - }, []); - - return ( -
- -
{'s c r o l l . '.repeat(100)}
-
- ); -}; -WithHTMLOverflowYScroll.storyName = 'With html.overflowY=scroll'; -WithHTMLOverflowYScroll.parameters = { creevey: { tests: testScrollLockUnlock } }; - -export const Multiple_WithScrollableContent: Story = () => ( - <> - - {renderScrollableContent()} - -); -Multiple_WithScrollableContent.parameters = { creevey: { tests: testScrollLockUnlock } }; diff --git a/packages/react-ui/internal/IgnoreLayerClick/__stories__/IgnoreLayerClick.stories.tsx b/packages/react-ui/internal/IgnoreLayerClick/__stories__/IgnoreLayerClick.stories.tsx deleted file mode 100644 index 850774022c6..00000000000 --- a/packages/react-ui/internal/IgnoreLayerClick/__stories__/IgnoreLayerClick.stories.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import React from 'react'; - -import { SidePage } from '../../../components/SidePage'; -import { IgnoreLayerClick } from '../IgnoreLayerClick'; -import { Button } from '../../../components/Button'; -import { Toggle } from '../../../components/Toggle'; - -interface SampleState { - open: boolean; - active: boolean; -} -class Sample extends React.Component { - public state: SampleState = { - active: false, - open: false, - }; - - public render() { - return ( -
- {this.state.open && ( - this.setState({ open: false })}> - Голова - -
Туловище
-
-
- )} - - - - - this.setState((state: SampleState) => { - return { active: !state.active }; - }) - } - /> -
- ); - } -} - -export default { title: 'IgnoreLayerClick', parameters: { creevey: { skip: true } } }; - -export const Common = () => ; diff --git a/packages/react-ui/internal/Menu/__stories__/Menu.stories.tsx b/packages/react-ui/internal/Menu/__stories__/Menu.stories.tsx deleted file mode 100644 index 83715bb4c0c..00000000000 --- a/packages/react-ui/internal/Menu/__stories__/Menu.stories.tsx +++ /dev/null @@ -1,261 +0,0 @@ -import React from 'react'; - -import { Meta, Story } from '../../../typings/stories'; -import { OkIcon } from '../../../internal/icons/16px'; -import { Menu } from '../Menu'; -import { MenuItem, MenuItemProps } from '../../../components/MenuItem'; -import { MenuHeader } from '../../../components/MenuHeader'; -import { MenuSeparator } from '../../../components/MenuSeparator'; - -export default { - title: 'Menu', - parameters: { creevey: { captureElement: '#menu-test-container' } }, - decorators: [ - (Story: () => JSX.Element) => ( - - ), - ], -} as Meta; - -export const WithItems = () => ( - - MenuItem1 - MenuItem2 - MenuItem3 - -); -WithItems.storyName = 'with Items'; - -export const WithItemsWithIcons = () => ( - - MenuHeader - }>MenuItem1 - }>MenuItem2 - MenuItem3 - -); - -export const WithItemsWithIconsWithoutTextAlignment = () => ( - - MenuHeader - }>MenuItem1 - }>MenuItem2 - MenuItem3 - -); - -WithItemsWithIconsWithoutTextAlignment.parameters = { - creevey: { skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }, -}; - -export const WithHeader = () => ( - - MenuHeader - MenuItem1 - MenuItem2 - MenuItem3 - -); -WithHeader.storyName = 'with Header'; - -export const WithSeparator = () => ( - - MenuHeader - MenuItem1 - - MenuItem2 - -); -WithSeparator.storyName = 'with Separator'; - -export const WithCustomChild = () => ( - - MenuHeader - MenuItem1 - - MenuItem2 -
- CustomChild -
-
-); -WithCustomChild.storyName = 'with Custom Child'; - -export const WithMaxHeight: Story = () => ( - - - MenuHeader - MenuItem1 - - MenuItem2 - MenuItem3 - MenuFooter - - -); -WithMaxHeight.storyName = 'with maxHeight'; - -WithMaxHeight.parameters = { - creevey: { - captureElement: '[data-tid="menu-container"', - skip: { - flacky: { in: ['chrome2022'] }, - }, - tests: { - async idle() { - await this.expect(await this.takeScreenshot()).to.matchImage('idle'); - }, - async 'moved up from top to the last Item'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#move-up' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('moved up from top to the last Item'); - }, - async 'moved up from bottom to the first Item'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#move-up' })) - .click(this.browser.findElement({ css: '#move-up' })) - .click(this.browser.findElement({ css: '#move-up' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('moved up from bottom to the first Item'); - }, - async 'moved down from top to the last Item'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#move-up' })) - .click(this.browser.findElement({ css: '#move-up' })) - .click(this.browser.findElement({ css: '#move-up' })) - .click(this.browser.findElement({ css: '#move-down' })) - .click(this.browser.findElement({ css: '#move-down' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('moved down from top to the last Item'); - }, - async 'moved down from bottom to the first Item'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#move-up' })) - .click(this.browser.findElement({ css: '#move-up' })) - .click(this.browser.findElement({ css: '#move-up' })) - .click(this.browser.findElement({ css: '#move-down' })) - .click(this.browser.findElement({ css: '#move-down' })) - .click(this.browser.findElement({ css: '#move-down' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('moved down from bottom to the first Item'); - }, - }, - }, -}; - -export const WithWidth = () => ( - - MenuHeader - MenuItem1 - - MenuItem2 - LongItem LongItem LongItem LongItem LongItem LongItem - -); -WithWidth.storyName = 'with width'; - -export const WithLongItems = () => ( - - MenuHeaderMenuHeaderMenuHeaderMenuHeader - MenuItem1 MenuItem1 MenuItem1 MenuItem1 MenuItem1 - - MenuItem2 - MenuItem3 - -); -WithLongItems.storyName = 'with long Items'; - -export const WithoutShadow = () => ( - - MenuHeader - MenuItem1 - - MenuItem2 - MenuItem3 - -); -WithoutShadow.storyName = 'without Shadow'; - -export const WithDisabledMenuItem: Story = () => ( - - MenuItem1 - MenuItem2 - -); -WithDisabledMenuItem.storyName = 'with disabled MenuItem'; - -WithDisabledMenuItem.parameters = { - creevey: { - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['mouseenter'] }, - }, - tests: { - async mouseenter() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="menuitem-notdisabled"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('mouseenter'); - }, - }, - }, -}; - -class MoveControls extends React.Component { - private menu: Menu | null = null; - - public render() { - return ( -
-
- - -
-
-
- {React.isValidElement(this.props.children) - ? React.cloneElement(this.props.children, { ref: this.refMenu } as MenuItemProps) - : this.props.children} -
-
- ); - } - - private refMenu = (el: Menu) => { - this.menu = el; - }; - - private moveUp = () => { - if (this.menu) { - this.menu.up(); - } - }; - - private moveDown = () => { - if (this.menu) { - this.menu.down(); - } - }; -} diff --git a/packages/react-ui/internal/PerformanceMetrics/__stories__/PerformanceMetrics.stories.tsx b/packages/react-ui/internal/PerformanceMetrics/__stories__/PerformanceMetrics.stories.tsx deleted file mode 100644 index f4a76e78cd8..00000000000 --- a/packages/react-ui/internal/PerformanceMetrics/__stories__/PerformanceMetrics.stories.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import React from 'react'; - -import { PerformanceMetrics } from '../PerformanceMetrics'; -import { Input } from '../../../components/Input'; -import { Tooltip } from '../../../components/Tooltip'; - -function getTooltipContent() { - return 'Tooltip content'; -} -const INPUTS_COUNT = 150; -const INPUT_WIDTH = 50; -const DUMMY = new Array(INPUTS_COUNT).fill(''); -const WRAPPER_STYLES = { marginRight: 10, marginBottom: 10, display: 'inline-block' }; - -const inputs = ( -
- {DUMMY.map((i, index) => ( -
- -
- ))} -
-); - -const inputsWithTooltip = ( -
- {DUMMY.map((i, index) => ( -
- - - -
- ))} -
-); - -export default { title: 'PerformanceMetrics', parameters: { creevey: { skip: true } } }; - -export const BareInputsVsTooltipInput = () => { - return ( -
- -
- ); -}; -BareInputsVsTooltipInput.storyName = 'Bare Inputs vs Tooltip+Input'; diff --git a/packages/react-ui/internal/Popup/__stories__/Popup.stories.tsx b/packages/react-ui/internal/Popup/__stories__/Popup.stories.tsx deleted file mode 100644 index e2d3a60652b..00000000000 --- a/packages/react-ui/internal/Popup/__stories__/Popup.stories.tsx +++ /dev/null @@ -1,612 +0,0 @@ -import React from 'react'; -import { DropdownProps } from 'react-ui'; - -import { Popup, PopupPositionsType, PopupProps } from '../Popup'; -import { Nullable } from '../../../typings/utility-types'; -import { Tooltip } from '../../../components/Tooltip'; -import { ComboBox } from '../../../components/ComboBox'; -import { Hint } from '../../../components/Hint'; -import { Select } from '../../../components/Select'; -import { RenderLayer } from '../../RenderLayer'; -import { isTestEnv } from '../../../lib/currentEnvironment'; -import { ThemeContext } from '../../../lib/theming/ThemeContext'; - -export default { title: 'Popup' }; - -export const AllPinOpened = () => ; -AllPinOpened.storyName = 'All pin opened'; - -export const AllPinOpenedOnSmallElements = () => ; -AllPinOpenedOnSmallElements.storyName = 'All pin opened on small elements'; - -export const PositioningStory = () => ; -PositioningStory.storyName = 'Positioning'; -PositioningStory.parameters = { creevey: { skip: true } }; - -export const DisableAnimations = () => ( -
- - -
-); -DisableAnimations.storyName = 'disableAnimations'; -DisableAnimations.parameters = { creevey: { skip: true } }; - -export const HintStory = () => ( -
- -
-); -HintStory.storyName = 'Hint'; - -export const ToastStory = () => ( -
- -
-); -ToastStory.storyName = 'Toast'; - -export const SmallWidth = () => ; -SmallWidth.storyName = 'Small width'; - -export const HoverBehaviourStory = () => ; -HoverBehaviourStory.storyName = 'Hover behaviour'; -HoverBehaviourStory.parameters = { creevey: { skip: true } }; - -const AllCases = ({ small, padding }: { small: boolean; padding: string }) => ( -
- - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - -
- - - - - - -
- - - - - - -
- - - - - - -
- - - - - - - -
-
-); - -const Positioning = () => ( -
- - - {new Array(6 * 5).fill(0).map((x, i) => { - return Math.floor(i / 6) % 2 ? ( - - - - ) : ( - - - - - - ); - })} - -
-
-
- - - - - - - -
-
-); - -class MinWidth extends React.Component { - public state: AlwaysOpenedState = { - anchor: null, - }; - - private anchor: Nullable; - - public componentDidMount() { - this.setState({ - anchor: this.anchor, - }); - } - - public render() { - return ( -
- (this.anchor = el)}>x - {this.state.anchor && ( - -
- {'21:00'} -
-
- )} -
- ); - } -} - -interface AlwaysOpenedProps { - small: boolean; - positions: PopupPositionsType[]; -} -interface AlwaysOpenedState { - anchor: Nullable; -} -class AlwaysOpened extends React.Component { - public state: AlwaysOpenedState = { - anchor: null, - }; - - private anchor: Nullable; - - public componentDidMount() { - this.setState({ - anchor: this.anchor, - }); - } - - public render() { - const defaultStyle: React.CSSProperties = { - width: '80px', - height: '70px', - margin: '20px', - border: '1px solid black', - textAlign: 'center', - fontSize: '40px', - }; - - const style: React.CSSProperties = this.props.small - ? { - ...defaultStyle, - width: '20', - height: '20', - margin: '50', - } - : defaultStyle; - - return ( - - {(theme) => { - return ( -
-
- x -
- {this.state.anchor && ( - -
- Text -
-
- )} -
- ); - }} -
- ); - } - - private _handleRef = (e: HTMLDivElement) => { - this.anchor = e; - }; -} - -interface PopupWithPositionsProps { - placeholder?: string; - disableAnimations?: boolean; -} -interface PopupWithPositionsState { - opened: boolean; - anchor: Nullable; -} -class PopupWithPositions extends React.Component { - public state: PopupWithPositionsState = { - opened: false, - anchor: null, - }; - - private anchor: Nullable; - - public componentDidMount() { - this.setState({ - anchor: this.anchor, - }); - } - - public render() { - return ( - - {(theme) => { - return ( -
-
- {this.state.anchor && ( - - -
- {this.props.placeholder || 'Placeholder'} -
-
-
- )} -
- ); - }} - - ); - } - - private _handleRef = (element: HTMLDivElement) => { - this.anchor = element; - }; - - private _handleClick = () => { - const currentOpened = this.state.opened; - this.setState({ opened: !currentOpened }); - }; - - private _clickHandler = () => { - this.setState({ opened: false }); - }; -} - -interface FakeHintProps { - positions: PopupPositionsType[]; - margin: number; -} -interface FakeHintState { - anchor: Nullable; -} -class FakeHint extends React.Component { - public state: FakeHintState = { - anchor: null, - }; - - private anchor: Nullable; - - public componentDidMount() { - this.setState({ - anchor: this.anchor, - }); - } - - public render() { - return ( - - {(theme) => { - return ( -
-
(this.anchor = e)} - style={{ width: '100px', height: '100px', border: '1px solid black' }} - > - Hello -
- {this.state.anchor && ( - - WorldWorldWorldWorldWorld - - )} -
- ); - }} -
- ); - } -} - -interface ToastProps { - positions: PopupPositionsType[]; -} -interface ToastState { - anchor: Nullable; -} -class Toast extends React.Component { - public state: ToastState = { - anchor: null, - }; - - private anchor: Nullable; - - public componentDidMount() { - this.setState({ - anchor: this.anchor, - }); - } - - public render() { - return ( -
-
(this.anchor = e)} style={{ width: '100px', height: '100px', border: '1px solid black' }}> - Hello -
- {this.state.anchor && ( - - WorldWorldWorldWorldWorld - - )} -
- ); - } -} - -const renderPopupContent = () => { - return Popup content; -}; - -const COMBOBOX_ITEMS = [ - { value: 1, label: 'First' }, - { value: 2, label: 'Second' }, -]; -const SELECT_ITEMS = COMBOBOX_ITEMS.map((i) => i.label); -const getComboboxItems = () => Promise.resolve(COMBOBOX_ITEMS); - -interface DropdownValue { - value: number; - label: string; -} - -interface HoverTestProps { - dropdownProps?: Pick; - popupProps?: Pick; - useText?: boolean; -} -interface HasDropdownState { - selected?: DropdownValue; -} -class TooltipWithCombobox extends React.Component { - public state: HasDropdownState = {}; - - public render() { - const tooltipProps = this.props.popupProps || {}; - const comboboxProps = this.props.dropdownProps || {}; - return ( - - {this.props.useText ? ( - 'Sample text' - ) : ( - - )} - - ); - } - private handleOnChange = (value: DropdownValue) => { - this.setState({ selected: value }); - }; -} - -class HintWithSelect extends React.Component { - public state: HasDropdownState = {}; - - public render() { - const hintProps = this.props.popupProps || {}; - const selectProps = this.props.dropdownProps || {}; - return ( - - {this.props.useText ? ( - 'Sample text' - ) : ( - - size={'large'} - items={SELECT_ITEMS} - value={this.state.selected} - onValueChange={this.handleOnChange} - {...selectProps} - /> - )} - - ); - } - private handleOnChange = (value: DropdownValue) => { - this.setState({ selected: value }); - }; -} - -const HOVER_CASES: HoverTestProps[] = [ - { - dropdownProps: { disablePortal: true }, - popupProps: { useWrapper: true }, - }, - { - dropdownProps: { disablePortal: true }, - popupProps: { useWrapper: false }, - }, - { - dropdownProps: { disablePortal: false }, - popupProps: { useWrapper: true }, - }, - { - dropdownProps: { disablePortal: false }, - popupProps: { useWrapper: false }, - }, - { - useText: true, - popupProps: { useWrapper: true }, - }, - { - useText: true, - popupProps: { useWrapper: false }, - }, -]; - -const DescribeProps = (props: HoverTestProps) => { - return ( - - {props.useText ? 'Text' : 'Component'} - {props.popupProps &&
} - {props.popupProps && `popupProps.useWrapper=${props.popupProps.useWrapper}`} - {props.dropdownProps &&
} - {props.dropdownProps && `dropdownProps.disablePortal=${props.dropdownProps.disablePortal}`} -
- ); -}; - -class HoverBehaviour extends React.Component { - public render() { - return ( - - - - - - - - - - {HOVER_CASES.map((props, index) => ( - - - - - - ))} - -
CaseTooltipHint
- - - - - -
- ); - } -} diff --git a/packages/react-ui/internal/PopupMenu/__stories__/PopupMenu.creevey.stories.tsx b/packages/react-ui/internal/PopupMenu/__stories__/PopupMenu.creevey.stories.tsx deleted file mode 100644 index 6fe37be43fa..00000000000 --- a/packages/react-ui/internal/PopupMenu/__stories__/PopupMenu.creevey.stories.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import React from 'react'; - -import { delay } from '../../../lib/utils'; -import { CreeveyTests, Meta, Story } from '../../../typings/stories'; -import { OkIcon } from '../../icons/16px'; -import { PopupMenu, PopupMenuDataTids } from '../PopupMenu'; -import { MenuItem } from '../../../components/MenuItem'; -import { MenuHeader } from '../../../components/MenuHeader'; -import { Button } from '../../../components/Button'; - -export default { - title: 'PopupMenu/Functional tests', - decorators: [ - (Story: () => JSX.Element) => ( -
- -
- ), - ], -} as Meta; - -const textAlignmentTests: CreeveyTests = { - async opened() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: `[data-tid~="${PopupMenuDataTids.caption}"]` })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened'); - }, -}; - -export const WithItems: Story = () => ( - Click me}> - MenuItem1 - MenuItem2 - MenuItem3 - -); -WithItems.parameters = { - creevey: { - tests: textAlignmentTests, - skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, - }, -}; -WithItems.storyName = 'with Items'; - -export const WithItemsWithIcons: Story = () => ( - Click me}> - MenuHeader - }>MenuItem1 - }>MenuItem2 - MenuItem3 - -); -WithItemsWithIcons.parameters = { - creevey: { - tests: textAlignmentTests, - skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, - }, -}; - -export const WithItemsWithIconsWithoutTextAlignment: Story = () => ( - Click me}> - MenuHeader - }>MenuItem1 - }>MenuItem2 - MenuItem3 - -); -WithItemsWithIconsWithoutTextAlignment.parameters = { - creevey: { - tests: textAlignmentTests, - skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, - }, -}; diff --git a/packages/react-ui/internal/ThemePlayground/__stories__/ThemePlayground.stories.tsx b/packages/react-ui/internal/ThemePlayground/__stories__/ThemePlayground.stories.tsx deleted file mode 100644 index 4f0a7843ce4..00000000000 --- a/packages/react-ui/internal/ThemePlayground/__stories__/ThemePlayground.stories.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import React from 'react'; - -import { Story } from '../../../typings/stories'; -import { ThemeContextPlayground } from '../ThemeContextPlayground'; -import { delay } from '../../../lib/utils'; - -export default { title: 'ThemeProvider' }; - -export const Playground: Story = () => ; -Playground.storyName = 'playground'; - -Playground.parameters = { - creevey: { - skip: { - 'repeating tests': { - tests: [ - 'default theme top', - 'default theme bottom', - 'dark theme top', - 'dark theme bottom', - 'default old theme top', - 'default old theme bottom', - 'flat old theme top', - 'flat old theme bottom', - 'theme 2022 top', - 'theme 2022 bottom', - 'theme 2022 dark top', - 'theme 2022 dark bottom', - ], - in: /^(?!\b(chrome|firefox)\b)/, - }, - }, - tests: { - async 'default theme top'() { - await this.expect(await this.browser.takeScreenshot()).to.matchImage('default theme top'); - }, - async 'default theme bottom'() { - await this.browser.executeScript(function () { - document.documentElement.scrollTop = document.documentElement.scrollHeight; - }); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('default theme bottom'); - }, - async 'dark theme top'() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-prop-id="dark"]' })) - .perform(); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('dark theme top'); - }, - async 'dark theme bottom'() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-prop-id="dark"]' })) - .perform(); - await this.browser.executeScript(function () { - document.documentElement.scrollTop = document.documentElement.scrollHeight; - }); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('dark theme bottom'); - }, - async 'default old theme top'() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-prop-id="defaultOld"]' })) - .perform(); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('default old theme top'); - }, - async 'default old theme bottom'() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-prop-id="defaultOld"]' })) - .perform(); - await this.browser.executeScript(function () { - document.documentElement.scrollTop = document.documentElement.scrollHeight; - }); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('default old theme bottom'); - }, - async 'flat old theme top'() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-prop-id="flatOld"]' })) - .perform(); - await delay(500); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('flat old theme top'); - }, - async 'flat old theme bottom'() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-prop-id="flatOld"]' })) - .perform(); - await this.browser.executeScript(function () { - document.documentElement.scrollTop = document.documentElement.scrollHeight; - }); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('flat old theme bottom'); - }, - async 'theme 2022 top'() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-prop-id="theme2022"]' })) - .perform(); - await delay(500); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('theme 2022 top'); - }, - async 'theme 2022 bottom'() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-prop-id="theme2022"]' })) - .perform(); - await this.browser.executeScript(function () { - document.documentElement.scrollTop = document.documentElement.scrollHeight; - }); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('theme 2022 bottom'); - }, - async 'theme 2022 dark top'() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-prop-id="theme2022Dark"]' })) - .perform(); - await delay(500); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('theme 2022 dark top'); - }, - async 'theme 2022 dark bottom'() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-prop-id="theme2022Dark"]' })) - .perform(); - await this.browser.executeScript(function () { - document.documentElement.scrollTop = document.documentElement.scrollHeight; - }); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('theme 2022 dark bottom'); - }, - }, - }, -}; diff --git a/packages/react-ui/internal/ThemeShowcase/__stories__/ThemeShowcase.stories.tsx b/packages/react-ui/internal/ThemeShowcase/__stories__/ThemeShowcase.stories.tsx deleted file mode 100644 index 4ea7af6e88b..00000000000 --- a/packages/react-ui/internal/ThemeShowcase/__stories__/ThemeShowcase.stories.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -import { ThemeShowcase } from '../ThemeShowcase'; - -export default { title: 'ThemeShowcase', parameters: { creevey: { skip: true } } }; - -export const Playground = () => ; diff --git a/packages/react-ui/internal/ZIndex/__stories__/ZIndex.stories.tsx b/packages/react-ui/internal/ZIndex/__stories__/ZIndex.stories.tsx deleted file mode 100644 index 556a1061e6d..00000000000 --- a/packages/react-ui/internal/ZIndex/__stories__/ZIndex.stories.tsx +++ /dev/null @@ -1,1156 +0,0 @@ -import React from 'react'; - -import { Dropdown } from '../../../components/Dropdown'; -import { Story } from '../../../typings/stories'; -import { Gapped } from '../../../components/Gapped'; -import { Modal } from '../../../components/Modal'; -import { Loader } from '../../../components/Loader'; -import { Select, SelectDataTids } from '../../../components/Select'; -import { Kebab } from '../../../components/Kebab'; -import { MenuItem } from '../../../components/MenuItem'; -import { Center } from '../../../components/Center'; -import { Hint, HintProps } from '../../../components/Hint'; -import { Tooltip, TooltipTrigger } from '../../../components/Tooltip'; -import { ZIndex } from '../ZIndex'; -import { Button } from '../../../components/Button'; -import { Toggle } from '../../../components/Toggle'; -import { Popup, PopupPositionsType } from '../../Popup'; -import { Toast } from '../../../components/Toast'; -import { Input } from '../../../components/Input'; -import { SidePage } from '../../../components/SidePage'; -import { ToastView } from '../../../components/Toast/ToastView'; -import { LoaderAndButton } from '../../../components/Loader/__stories__/LoaderAndButton'; -import { DropdownMenu } from '../../../components/DropdownMenu'; -import { Sticky } from '../../../components/Sticky'; -import { delay } from '../../../lib/utils'; -import { ThemeContext } from '../../../lib/theming/ThemeContext'; - -const linearLightGradient = `repeating-linear-gradient( - 60deg, - #fafafa, - #fafafa 20px, - #dfdede 20px, - #dfdede 40px - )`; -const linearDarkGradient = `repeating-linear-gradient( - 60deg, - #868b8e, - #868b8e 20px, - #444 20px, - #444 40px - )`; - -class ZKebab extends React.Component { - public render() { - return ( - - 1 - 2 - 3 - 4 - 5 - 6 - - ); - } -} - -class ZSelect extends React.Component { - public render() { - return - -); - -const ModalWrapper = ({ caption = 'Title', ...props }: { caption?: string; children?: React.ReactChild }) => ( - - {caption} - {props.children} - - -); - -class LoaderCoversTooltip extends React.Component { - public render() { - return ( -
- -
- - -
- ); - } -} - -class ModalWithTooltipInLoader extends React.Component { - public render() { - return ( - -
- - - -
-
- ); - } -} - -class TooltipNearLoader extends React.Component { - public render() { - return ( -
- -
- - -
- -
-
- ); - } -} - -class NestedElementsInLoader extends React.Component { - public renderNestedModal() { - return ( - - - - ); - } - - public render() { - return ( - -
- -
- - {this.renderNestedModal()} - -
-
-
-
- ); - } -} - -interface HintAndModalState { - modalOpened: boolean; - hintOpened: HintProps['opened']; -} -class HintAndModal extends React.Component { - public state: HintAndModalState = { - modalOpened: false, - hintOpened: false, - }; - - public renderModal() { - return ( - - Title - -
-

- Use rxjs operators with react hooks. Use rxjs operators with react hooksUse rxjs operators with react - hooksUse rxjs operators with react hooksUse rxjs operators with react hooksUse rxjs operators with react - hooksUse rxjs operators with react hooksUse rxjs operators with react hooksUse rxjs operators with react - hooks -

-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
- - - -
- ); - } - - public open = () => { - this.setState({ modalOpened: true }); - }; - - public close = () => { - this.setState({ modalOpened: false }); - }; - - public render() { - return ( -
- {this.state.modalOpened && this.renderModal()} - - - -
- ); - } -} - -interface TooltipAndDropdownMenuState { - trigger: TooltipTrigger; -} -class TooltipAndSelect extends React.Component { - public state: TooltipAndDropdownMenuState = { - trigger: 'closed', - }; - - public render() { - const tooltipRender = () => ( -
- Задача организации, в особенности же рамки и место обучения кадров влечет за собой процесс внедрения и - модернизации форм развития. -
- ); - - return ( -
- - - Открыть меню}> - Раз - Два - Три - - - -
-
- - - Активировать - - - ); - } - - private setActive = (active: boolean) => this.setState({ active }); -} - -class LoaderAndSidePage extends React.Component { - public state = { active: false }; - public render() { - const { active } = this.state; - return ( -
- - Title - - -

Use rxjs operators with react hooks

-
-
- - Активировать - -
- -
- -
-
-
- ); - } - private setActive = (active: boolean) => this.setState({ active }); -} - -function ModalInLoaderAndModal() { - return ( -
- - - 1 - -

Ехал модал через реку

-

Видит модал в реке модал

-

Cунул модал модал в модал

-

Модал модал модал модал

-
- - - -
-
- - - 2 - - Ехал модал через реку, видит модал в реке модал, сунул модал модал в модал, модал модал модал модал - - - - - -
- ); -} - -function StickyAndLoader() { - return ( - <> - - {Array.from({ length: 8 }).map((_, i) => ( -
-

Ехал лоадер через реку

-

Видит лоадер в реке стики

-

Cунул лоадер лоадер в стики

-

Стики лоадер лоадер стики

-
-
- ))} - -

I'm Sticky inside Loader

-
-
- -

Sticky outsider

-
- - ); -} - -function StickyAndTooltips() { - return ( -
-
-
-
Click me!
}> - Plain text +
+); +InputAndText.storyName = 'Input and text'; + +export const ButtonWithoutContentInFlex = () => ( +
+
+); +ButtonWithoutContentInFlex.storyName = 'Button without content in flex-container'; +ButtonWithoutContentInFlex.parameters = { creevey: { skip: true } }; + +export const ButtonWithContentInFlex = () => ( +
+ Plain text +
+); +ButtonWithContentInFlex.storyName = 'Button with content in flex-container'; +ButtonWithContentInFlex.parameters = { creevey: { skip: true } }; + +export const InputWithButton = () => ; +InputWithButton.storyName = 'Input with button'; +InputWithButton.parameters = { creevey: { skip: true } }; + +export const TextInputInputLikeText = () => ( +
+ Text + + + Promise.resolve([])} + /> +
+); +TextInputInputLikeText.storyName = 'Text, Input, InputLikeText'; + +export const TextLargeInput = () => ( +
+ Text + +
+); +TextLargeInput.storyName = 'Text, Large Input'; + +export const TextButtons = () => ( +
+ Text + + +
+); +TextButtons.storyName = 'Text, Buttons'; + +export const TextLargeButton = () => ( +
+ Text + +
+); +TextLargeButton.storyName = 'Text, Large Button'; + +export const TextSpinner = () => ( +
+ Text + +
+); +TextSpinner.storyName = 'Text, Spinner'; + +export const IconSpinner = () => ( +
+ + +
+); +IconSpinner.storyName = 'Icon, Spinner'; + +export const Checkboxes = () => ( +
+ Lorem dolor a L1{' '} + L1.1elit. amet. +
+ Lorem ipsum dolor Label 2 sit amet{' '} + sit. +
+); +Checkboxes.storyName = 'Checkbox'; + +const BaselineFont: React.FC<{ + fontFamily: string; + size: SizeProp; + bg: string; + width?: string; +}> = ({ fontFamily, size, width = '120px', bg }) => { + const content = size.charAt(0).toUpperCase(); + return ( +
+ +
{fontFamily}
+ + Ok + }>Ok + }> + Ok + + Tg + + + Ch + + + Ch + + + + Rd + + + + }>Menu + + + Menu + + + Promise.resolve([])} + size={size} + /> + + + + + +
+
+ ); +}; + +const BaselineSize: React.FC<{ size: SizeProp; bg: string; width?: string }> = ({ size, bg, width }) => ( +
+ + {['Arial', 'Lab Grotesque', 'Segoe UI', 'Times New Roman'].map((fontFamily, i) => ( + + ))} + +
+); + +export const DifferentFontsAndSizes = () => ( + +); +DifferentFontsAndSizes.storyName = 'Different fonts in small'; + +export const NewStoryDifferentFontsAndSizesThemeM = () => ; +NewStoryDifferentFontsAndSizesThemeM.storyName = 'Different fonts in medium'; + +class DifferentFontsAndSizesThemeM extends React.Component { + public render() { + return ( +
+ + {(theme) => ( + + + + )} + +
+ ); + } +} + +export const NewStoryDifferentFontsAndSizesThemeL = () => ; +NewStoryDifferentFontsAndSizesThemeL.storyName = 'Different fonts in large'; + +class DifferentFontsAndSizesThemeL extends React.Component { + public render() { + return ( +
+ + {(theme) => ( + + + + )} + +
+ ); + } +} + +class SimpleForm extends React.Component { + public state = { + isFormSubmitted: false, + value: '', + }; + + public render() { + return ( +
+
{ + e.preventDefault(); + this.setState({ isFormSubmitted: true }); + }} + > + this.setState({ value })} /> + +
+ {this.state.isFormSubmitted && {this.state.value}} +
+ ); + } +} From 4af759e5bdc6fb36b658fc00f3df51bafff0e95d Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Wed, 8 May 2024 14:02:53 +0500 Subject: [PATCH 019/197] chore: fix Calendar test --- .../chromeDark/DateSelect months.png | 3 - .../firefoxDark/DateSelect months.png | 3 - .../ie11/DateSelect months.png | 0 .../chromeDark/DateSelect years.png | 3 - .../firefoxDark/DateSelect years.png | 3 - .../ie11/DateSelect years.png | 0 .../chrome/DateSelect months.png | 3 - .../firefox/DateSelect months.png | 3 - .../chrome/DateSelect years.png | 3 - .../firefox/DateSelect years.png | 3 - .../initial date/chrome/initial date.png | 0 .../initial date/firefox/initial date.png | 0 .../initial date/ie11/initial date.png | 0 .../scrolls to new date on date change.png | 0 .../scrolls to new date on date change.png | 0 .../scrolls to new date on date change.png | 0 .../Calendar/__creevey__/Calendar.creevey.ts | 80 +++++++++++++++++++ .../Calendar/__stories__/Calendar.stories.tsx | 55 +++++++++++++ 18 files changed, 135 insertions(+), 24 deletions(-) delete mode 100644 packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect months/chromeDark/DateSelect months.png delete mode 100644 packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect months/firefoxDark/DateSelect months.png rename packages/react-ui/.creevey/images/Calendar/{Functional tests => }/Calendar with min max date/DateSelect months/ie11/DateSelect months.png (100%) delete mode 100644 packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect years/chromeDark/DateSelect years.png delete mode 100644 packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect years/firefoxDark/DateSelect years.png rename packages/react-ui/.creevey/images/Calendar/{Functional tests => }/Calendar with min max date/DateSelect years/ie11/DateSelect years.png (100%) delete mode 100644 packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect months/chrome/DateSelect months.png delete mode 100644 packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect months/firefox/DateSelect months.png delete mode 100644 packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect years/chrome/DateSelect years.png delete mode 100644 packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect years/firefox/DateSelect years.png rename packages/react-ui/.creevey/images/Calendar/{Functional tests => }/Scrolls Calendar on date change/initial date/chrome/initial date.png (100%) rename packages/react-ui/.creevey/images/Calendar/{Functional tests => }/Scrolls Calendar on date change/initial date/firefox/initial date.png (100%) rename packages/react-ui/.creevey/images/Calendar/{Functional tests => }/Scrolls Calendar on date change/initial date/ie11/initial date.png (100%) rename packages/react-ui/.creevey/images/Calendar/{Functional tests => }/Scrolls Calendar on date change/scrolls to new date on date change/chrome/scrolls to new date on date change.png (100%) rename packages/react-ui/.creevey/images/Calendar/{Functional tests => }/Scrolls Calendar on date change/scrolls to new date on date change/firefox/scrolls to new date on date change.png (100%) rename packages/react-ui/.creevey/images/Calendar/{Functional tests => }/Scrolls Calendar on date change/scrolls to new date on date change/ie11/scrolls to new date on date change.png (100%) create mode 100644 packages/react-ui/components/Calendar/__creevey__/Calendar.creevey.ts create mode 100644 packages/react-ui/components/Calendar/__stories__/Calendar.stories.tsx diff --git a/packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect months/chromeDark/DateSelect months.png b/packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect months/chromeDark/DateSelect months.png deleted file mode 100644 index b4435cd38cc..00000000000 --- a/packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect months/chromeDark/DateSelect months.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d45a0b85fb05fa23477f3067c9c53ee4f25f0a45eee6c1f8c1a52a3308251a14 -size 25993 diff --git a/packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect months/firefoxDark/DateSelect months.png b/packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect months/firefoxDark/DateSelect months.png deleted file mode 100644 index 872101f979c..00000000000 --- a/packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect months/firefoxDark/DateSelect months.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b55a3b842796d468a4754488b95e08e8a8156d02cb51926341b7ea922dc9981d -size 28271 diff --git a/packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect months/ie11/DateSelect months.png b/packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect months/ie11/DateSelect months.png similarity index 100% rename from packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect months/ie11/DateSelect months.png rename to packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect months/ie11/DateSelect months.png diff --git a/packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect years/chromeDark/DateSelect years.png b/packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect years/chromeDark/DateSelect years.png deleted file mode 100644 index 9df9ac62728..00000000000 --- a/packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect years/chromeDark/DateSelect years.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f5ad26a4091e934e00ee60db278ecc1e3c68b6b10d7f3db5bb1fca3b3a5a72f8 -size 23275 diff --git a/packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect years/firefoxDark/DateSelect years.png b/packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect years/firefoxDark/DateSelect years.png deleted file mode 100644 index 5004e4153f8..00000000000 --- a/packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect years/firefoxDark/DateSelect years.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fd0409cd0eed493b649e89b37c8c90e41f568f7db9b55b97debb2f49ee86d6ff -size 26474 diff --git a/packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect years/ie11/DateSelect years.png b/packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect years/ie11/DateSelect years.png similarity index 100% rename from packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect years/ie11/DateSelect years.png rename to packages/react-ui/.creevey/images/Calendar/Calendar with min max date/DateSelect years/ie11/DateSelect years.png diff --git a/packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect months/chrome/DateSelect months.png b/packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect months/chrome/DateSelect months.png deleted file mode 100644 index 317c6d7324b..00000000000 --- a/packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect months/chrome/DateSelect months.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:efe79a33c42c21ca6eb10f058b25ef664ec78dde420b35422effa7e3d954bf87 -size 25159 diff --git a/packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect months/firefox/DateSelect months.png b/packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect months/firefox/DateSelect months.png deleted file mode 100644 index 966c7aa41f0..00000000000 --- a/packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect months/firefox/DateSelect months.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1dbe4467200cd28e88b5b6e8ac76f914daa89929714c980a52bc80e1bfd1cec3 -size 26593 diff --git a/packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect years/chrome/DateSelect years.png b/packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect years/chrome/DateSelect years.png deleted file mode 100644 index 9b7f86f3f8d..00000000000 --- a/packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect years/chrome/DateSelect years.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3afe3948a6c8dad1fe37358f17e7127ad43d678721a4182d8382d01d64d97c91 -size 22214 diff --git a/packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect years/firefox/DateSelect years.png b/packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect years/firefox/DateSelect years.png deleted file mode 100644 index 4b6ceb1ec12..00000000000 --- a/packages/react-ui/.creevey/images/Calendar/Functional tests/Calendar with min max date/DateSelect years/firefox/DateSelect years.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:035ac8727211a926cd3f08cbb86736d952e2626be04430ddf9f2ae0236a61b49 -size 25389 diff --git a/packages/react-ui/.creevey/images/Calendar/Functional tests/Scrolls Calendar on date change/initial date/chrome/initial date.png b/packages/react-ui/.creevey/images/Calendar/Scrolls Calendar on date change/initial date/chrome/initial date.png similarity index 100% rename from packages/react-ui/.creevey/images/Calendar/Functional tests/Scrolls Calendar on date change/initial date/chrome/initial date.png rename to packages/react-ui/.creevey/images/Calendar/Scrolls Calendar on date change/initial date/chrome/initial date.png diff --git a/packages/react-ui/.creevey/images/Calendar/Functional tests/Scrolls Calendar on date change/initial date/firefox/initial date.png b/packages/react-ui/.creevey/images/Calendar/Scrolls Calendar on date change/initial date/firefox/initial date.png similarity index 100% rename from packages/react-ui/.creevey/images/Calendar/Functional tests/Scrolls Calendar on date change/initial date/firefox/initial date.png rename to packages/react-ui/.creevey/images/Calendar/Scrolls Calendar on date change/initial date/firefox/initial date.png diff --git a/packages/react-ui/.creevey/images/Calendar/Functional tests/Scrolls Calendar on date change/initial date/ie11/initial date.png b/packages/react-ui/.creevey/images/Calendar/Scrolls Calendar on date change/initial date/ie11/initial date.png similarity index 100% rename from packages/react-ui/.creevey/images/Calendar/Functional tests/Scrolls Calendar on date change/initial date/ie11/initial date.png rename to packages/react-ui/.creevey/images/Calendar/Scrolls Calendar on date change/initial date/ie11/initial date.png diff --git a/packages/react-ui/.creevey/images/Calendar/Functional tests/Scrolls Calendar on date change/scrolls to new date on date change/chrome/scrolls to new date on date change.png b/packages/react-ui/.creevey/images/Calendar/Scrolls Calendar on date change/scrolls to new date on date change/chrome/scrolls to new date on date change.png similarity index 100% rename from packages/react-ui/.creevey/images/Calendar/Functional tests/Scrolls Calendar on date change/scrolls to new date on date change/chrome/scrolls to new date on date change.png rename to packages/react-ui/.creevey/images/Calendar/Scrolls Calendar on date change/scrolls to new date on date change/chrome/scrolls to new date on date change.png diff --git a/packages/react-ui/.creevey/images/Calendar/Functional tests/Scrolls Calendar on date change/scrolls to new date on date change/firefox/scrolls to new date on date change.png b/packages/react-ui/.creevey/images/Calendar/Scrolls Calendar on date change/scrolls to new date on date change/firefox/scrolls to new date on date change.png similarity index 100% rename from packages/react-ui/.creevey/images/Calendar/Functional tests/Scrolls Calendar on date change/scrolls to new date on date change/firefox/scrolls to new date on date change.png rename to packages/react-ui/.creevey/images/Calendar/Scrolls Calendar on date change/scrolls to new date on date change/firefox/scrolls to new date on date change.png diff --git a/packages/react-ui/.creevey/images/Calendar/Functional tests/Scrolls Calendar on date change/scrolls to new date on date change/ie11/scrolls to new date on date change.png b/packages/react-ui/.creevey/images/Calendar/Scrolls Calendar on date change/scrolls to new date on date change/ie11/scrolls to new date on date change.png similarity index 100% rename from packages/react-ui/.creevey/images/Calendar/Functional tests/Scrolls Calendar on date change/scrolls to new date on date change/ie11/scrolls to new date on date change.png rename to packages/react-ui/.creevey/images/Calendar/Scrolls Calendar on date change/scrolls to new date on date change/ie11/scrolls to new date on date change.png diff --git a/packages/react-ui/components/Calendar/__creevey__/Calendar.creevey.ts b/packages/react-ui/components/Calendar/__creevey__/Calendar.creevey.ts new file mode 100644 index 00000000000..c30fcaa4c68 --- /dev/null +++ b/packages/react-ui/components/Calendar/__creevey__/Calendar.creevey.ts @@ -0,0 +1,80 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('Calendar', () => { + story('CalendarWithMinMaxDate', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + test('DateSelect months', async function () { + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Calendar"]' })) + .perform(); + await delay(1000); + await this.browser + .actions({ bridge: true }) + .click( + this.browser.findElement({ + css: '[data-tid="MonthView__month"]:first-child [data-tid="MonthView__headerMonth"] [data-tid="DateSelect__caption"]', + }), + ) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('DateSelect months'); + }); + + test('DateSelect years', async function () { + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Calendar"]' })) + .perform(); + await delay(1000); + await this.browser + .actions({ bridge: true }) + .click( + this.browser.findElement({ + css: '[data-comp-name~="MonthView"]:first-child [data-tid="MonthView__headerYear"] [data-tid="DateSelect__caption"]', + }), + ) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('DateSelect years'); + }); + }); + + story('ScrollsCalendarOnDateChange', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + test('initial date', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('initial date'); + }); + + test('scrolls to new date on date change', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="change-date-button"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('scrolls to new date on date change'); + }); + }); + + story('CalendarWithBottomSeparator', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + "8px and 2022 themes don't affect the bottom separator": { + in: /^(?!\b(chrome|chromeDark|firefox|firefoxDark)\b)/, + }, + }, + }); + }); +}); diff --git a/packages/react-ui/components/Calendar/__stories__/Calendar.stories.tsx b/packages/react-ui/components/Calendar/__stories__/Calendar.stories.tsx new file mode 100644 index 00000000000..df063d780ba --- /dev/null +++ b/packages/react-ui/components/Calendar/__stories__/Calendar.stories.tsx @@ -0,0 +1,55 @@ +import React, { useState } from 'react'; +import { action } from '@storybook/addon-actions'; + +import { Calendar } from '../Calendar'; +import { Story } from '../../../typings/stories'; +import { Gapped } from '../../Gapped'; +import { LocaleContext } from '../../../lib/locale'; +import { InternalDateOrder, InternalDateSeparator } from '../../../lib/date/types'; + +export default { title: 'Calendar' }; + +export const CalendarWithBottomSeparator: Story = () => { + const [date, setDate] = React.useState('12.05.2022'); + + return ; +}; +CalendarWithBottomSeparator.storyName = 'Calendar with bottom separator'; + +export const CalendarWithMinMaxDate: Story = () => { + const [min, setMin] = React.useState('02.07.2017'); + const [max, setMax] = React.useState('30.01.2020'); + + return ( + + + + + + + + ); +}; +CalendarWithMinMaxDate.storyName = 'Calendar with min max date'; + +export const ScrollsCalendarOnDateChange: Story = () => { + const [date, setDate] = useState('01.01.2001'); + + return ( + <> + + + + ); +}; +ScrollsCalendarOnDateChange.storyName = 'Scrolls Calendar on date change'; From a51a27323782a30397957d28bc7238ca81cc46c3 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Wed, 8 May 2024 15:11:22 +0500 Subject: [PATCH 020/197] chore: fix Center test --- .../components/Center/__stories__/Center.stories.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 packages/react-ui/components/Center/__stories__/Center.stories.tsx diff --git a/packages/react-ui/components/Center/__stories__/Center.stories.tsx b/packages/react-ui/components/Center/__stories__/Center.stories.tsx new file mode 100644 index 00000000000..c4fbb035030 --- /dev/null +++ b/packages/react-ui/components/Center/__stories__/Center.stories.tsx @@ -0,0 +1,12 @@ +import React from 'react'; + +import { Center } from '../Center'; + +export default { title: 'Center', parameters: { creevey: { skip: true } } }; + +export const Simple = () => ( +
+
Hola
+
+); +Simple.storyName = 'simple'; From 8d7871f9f29a3aca80c352de84410d383ae52962 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Wed, 8 May 2024 15:11:33 +0500 Subject: [PATCH 021/197] chore: fix Checkbox test --- .../Checkbox/__creevey__/Checkbox.creevey.ts | 282 ++++++++++++++++++ .../Checkbox/__stories__/Checkbox.stories.tsx | 235 +++++++++++++++ 2 files changed, 517 insertions(+) create mode 100644 packages/react-ui/components/Checkbox/__creevey__/Checkbox.creevey.ts create mode 100644 packages/react-ui/components/Checkbox/__stories__/Checkbox.stories.tsx diff --git a/packages/react-ui/components/Checkbox/__creevey__/Checkbox.creevey.ts b/packages/react-ui/components/Checkbox/__creevey__/Checkbox.creevey.ts new file mode 100644 index 00000000000..b91057f9721 --- /dev/null +++ b/packages/react-ui/components/Checkbox/__creevey__/Checkbox.creevey.ts @@ -0,0 +1,282 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +const checkboxTests = () => { + test('idle', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('idle'); + }); + + test('hovered', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ + css: '[data-tid~="test-checkbox"]', + }), + }) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); + }); + + test('pressed', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ + css: '[data-tid~="test-checkbox"]', + }), + }) + .press() + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('pressed'); + await this.browser + .actions({ + bridge: true, + }) + .release() + .perform(); + }); + + test('clicked', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="test-checkbox"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); + }); + + test('tabPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="test-checkbox"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .move({ origin: this.browser.findElement({ css: 'body' }) }) + .press() + .release() + .sendKeys(this.keys.TAB) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); + }); + + test('spacePress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="test-checkbox"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .move({ origin: this.browser.findElement({ css: 'body' }) }) + .press() + .release() + .sendKeys(this.keys.TAB) + .perform(); + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.SPACE) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('spacePress'); + }); +}; + +kind('Checkbox', () => { + story('Plain', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { + in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], + tests: 'hovered', + }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'pressed', 'clicked'], + }, + }, + }); + + checkboxTests(); + }); + + story('Checked', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { + in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], + tests: 'hovered', + }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'pressed', 'clicked'], + }, + }, + }); + test('idle', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('idle'); + }); + + test('hovered', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ + css: '[data-tid~="test-checkbox"]', + }), + }) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); + }); + + test('pressed', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ + css: '[data-tid~="test-checkbox"]', + }), + }) + .press() + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('pressed'); + await this.browser + .actions({ + bridge: true, + }) + .release() + .perform(); + }); + }); + + story('Indeterminate', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { + in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], + tests: 'hovered', + }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'clicked'], + }, + }, + }); + + test('plain', async function () { + const element = await this.browser.findElement({ + css: '#screenshot-capture', + }); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('plain'); + }); + + test('hovered', async function () { + const element = await this.browser.findElement({ + css: '#screenshot-capture', + }); + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: 'label' }), + }) + .perform(); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('hovered'); + }); + + test('tabPress', async function () { + const element = await this.browser.findElement({ + css: '#screenshot-capture', + }); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('tabPress'); + }); + + test('clicked', async function () { + const element = await this.browser.findElement({ + css: '#screenshot-capture', + }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'label' })) + .perform(); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('clicked'); + }); + }); + + story('Highlighted', () => { + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('tabPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); + }); + }); + + story('CheckboxLabelSelectionWithPressedShift', () => { + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('selected with pressed shift', async function () { + const checkbox = await this.browser.findElement({ + css: '[data-comp-name~="Checkbox"]', + }); + await this.browser.actions({ bridge: true }).keyDown(this.keys.SHIFT).click(checkbox).perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('selected with pressed shift'); + await this.browser.actions({ bridge: true }).keyUp(this.keys.SHIFT).perform(); + }); + }); +}); diff --git a/packages/react-ui/components/Checkbox/__stories__/Checkbox.stories.tsx b/packages/react-ui/components/Checkbox/__stories__/Checkbox.stories.tsx new file mode 100644 index 00000000000..1c03d55c9f8 --- /dev/null +++ b/packages/react-ui/components/Checkbox/__stories__/Checkbox.stories.tsx @@ -0,0 +1,235 @@ +import React, { useState } from 'react'; + +import { Meta, Story } from '../../../typings/stories'; +import { Checkbox } from '../Checkbox'; +import { Gapped } from '../../Gapped'; +import { Nullable } from '../../../typings/utility-types'; +import { SizeProp } from '../../../lib/types/props'; + +interface PlainCheckboxState { + checked: false; + size?: SizeProp; +} +class PlainCheckbox extends React.Component { + public state: PlainCheckboxState = { + checked: false, + }; + + public render() { + const { checked, size } = this.state; + return ( + this.setState({ checked: !checked })} + checked={checked} + size={size} + data-tid="test-checkbox" + > + {this.props.children} + + ); + } +} + +interface IndeterminatePlaygroundState { + checked: boolean; +} + +class IndeterminatePlayground extends React.Component { + public state: IndeterminatePlaygroundState = { + checked: false, + }; + + private checkbox: Checkbox | null = null; + + public render() { + return ( +
+ + this.setState({ checked })} + checked={this.state.checked} + initialIndeterminate + ref={this.checkboxRef} + > + {this.props.children} + + +
+ + + +
+
+ ); + } + + private checkboxRef = (element: Checkbox) => { + this.checkbox = element; + }; + + private setIndeterminate = () => { + if (this.checkbox) { + this.checkbox.setIndeterminate(); + } + }; + + private resetIndeterminate = () => { + if (this.checkbox) { + this.checkbox.resetIndeterminate(); + } + }; + + private changeValue = () => { + this.setState((state: IndeterminatePlaygroundState) => ({ + checked: !state.checked, + })); + }; +} + +export default { title: 'Checkbox' } as Meta; + +export const Plain: Story = () => Plain checkbox; +Plain.storyName = 'plain'; + +export const Unchecked = () => Unchecked; +Unchecked.storyName = 'unchecked'; +Unchecked.parameters = { creevey: { skip: true } }; + +export const Checked = () => ( + + Checked + +); +Checked.storyName = 'checked'; + +export const Disabled = () => Disabled; +Disabled.storyName = 'disabled'; + +export const DisabledChecked = () => ( + + Disabled and checked + +); +DisabledChecked.storyName = 'disabled checked'; + +export const Error = () => ( + + Error + + Error and Disabled + + +); +Error.storyName = 'error'; + +export const WithMouseEnterLeaveHandlers = () => ( + console.count('enter')} onMouseLeave={() => console.count('leave')}> + Hover me + +); +WithMouseEnterLeaveHandlers.storyName = 'with mouse enter/leave handlers'; +WithMouseEnterLeaveHandlers.parameters = { creevey: { skip: true } }; + +export const WithALongLabel = () => ( +
+ Lorem ipsum dolor --{' '} + + Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. + Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + {' '} + -- Lorem ipsum dolor. +
+); +WithALongLabel.storyName = 'with a long label'; + +export const WithoutLabel = () => ( +
+
+ Some text +
+
+ Some text Label +
+
+); +WithoutLabel.storyName = 'without label'; + +export const ProgrammaticFocus = () => { + let checkbox: Nullable; + + function focus() { + if (checkbox) { + checkbox.focus(); + } + } + + function blur() { + if (checkbox) { + checkbox.blur(); + } + } + + return ( +
+ (checkbox = el)}>Label + + + + +
+ ); +}; +ProgrammaticFocus.storyName = 'programmatic focus'; +ProgrammaticFocus.parameters = { creevey: { skip: true } }; + +export const Indeterminate: Story = () => Label; +Indeterminate.storyName = 'indeterminate'; + +export const Highlighted: Story = () => { + return ( +
+ + Highlighted default + + Highlighted warning + + + Highlighted error + + +
+ ); +}; +Highlighted.storyName = 'highlighted'; + +export const CheckboxLabelSelectionWithPressedShift: Story = () => { + const [checked, setChecked] = useState(false); + + return ( + + caption + + ); +}; +CheckboxLabelSelectionWithPressedShift.storyName = 'checkbox label selection with pressed shift'; + +export const Size: Story = () => { + return ( +
+ + Size: small + Size: medium + Size: large + +
+ ); +}; +Size.storyName = 'size'; From 00ae528dcb199853e1ea4cc68f2ca5ae3bf9bbcc Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Wed, 8 May 2024 16:26:52 +0500 Subject: [PATCH 022/197] chore: fix Combobox test --- .../ComboBox/__creevey__/ComboBox.creevey.ts | 601 ++++++++++++ .../ComboBox/__stories__/Combobox.stories.tsx | 913 ++++++++++++++++++ 2 files changed, 1514 insertions(+) create mode 100644 packages/react-ui/components/ComboBox/__creevey__/ComboBox.creevey.ts create mode 100644 packages/react-ui/components/ComboBox/__stories__/Combobox.stories.tsx diff --git a/packages/react-ui/components/ComboBox/__creevey__/ComboBox.creevey.ts b/packages/react-ui/components/ComboBox/__creevey__/ComboBox.creevey.ts new file mode 100644 index 00000000000..be4430a41e1 --- /dev/null +++ b/packages/react-ui/components/ComboBox/__creevey__/ComboBox.creevey.ts @@ -0,0 +1,601 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('ComboBox', () => { + story('SimpleComboboxStory', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { + in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark', 'ie112022', 'ie112022Dark'], + tests: ['hovered', 'selected_2', 'select_1'], + }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered'], + }, + }, + }); + + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('opened', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); + + test('hovered', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ + css: '[data-comp-name~="MenuItem"]:nth-of-type(4)', + }), + }) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); + }); + + test('selected', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ + css: '[data-comp-name~="MenuItem"]:nth-of-type(4)', + }), + }) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .press() + .release() + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('selected'); + }); + + test('search result', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('Second') + .perform(); + await delay(500); + await this.expect(await this.takeScreenshot()).to.matchImage('search result'); + }); + + test('selcted', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('Second') + .perform(); + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ENTER) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('selcted'); + }); + + test('opened again', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('Second') + .perform(); + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ENTER) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Input"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('opened again'); + }); + + test('search result_0', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('Такого точно нету') + .perform(); + await delay(500); + await this.expect(await this.takeScreenshot()).to.matchImage('search result_0'); + }); + + test('select', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ARROW_DOWN) + .sendKeys(this.keys.ARROW_DOWN) + .sendKeys(this.keys.ARROW_DOWN) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('select'); + }); + + test('submit', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ARROW_DOWN) + .sendKeys(this.keys.ARROW_DOWN) + .sendKeys(this.keys.ARROW_DOWN) + .sendKeys(this.keys.ENTER) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('submit'); + }); + + test('select_1', async function () { + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await delay(500); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('Second') + .perform(); + await delay(500); + await this.browser + .actions({ + bridge: true, + }) + .move({ origin: this.browser.findElement({ css: 'body' }) }) + .perform(); + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .press() + .release() + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('select_1'); + }); + + test('selected_2', async function () { + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await delay(500); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('Second') + .perform(); + await delay(500); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'body' })) + .perform(); + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('selected_2'); + }); + }); + + story('OpenToTop', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { + in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], + tests: 'hovered', + }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered'], + }, + }, + }); + + test('plain', async function () { + const element = await this.browser.findElement({ + css: '[data-tid="container"]', + }); + await this.expect(await element.takeScreenshot()).to.matchImage('plain'); + }); + + test('opened', async function () { + const element = await this.browser.findElement({ + css: '[data-tid="container"]', + }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.expect(await element.takeScreenshot()).to.matchImage('opened'); + }); + + test('hovered', async function () { + const element = await this.browser.findElement({ + css: '[data-tid="container"]', + }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ + css: '[data-comp-name~="MenuItem"]:nth-of-type(4)', + }), + }) + .perform(); + await this.expect(await element.takeScreenshot()).to.matchImage('hovered'); + }); + + test('selected', async function () { + const element = await this.browser.findElement({ + css: '[data-tid="container"]', + }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ + css: '[data-comp-name~="MenuItem"]:nth-of-type(4)', + }), + }) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .press() + .release() + .perform(); + await this.expect(await element.takeScreenshot()).to.matchImage('selected'); + }); + }); + + story('AlwaysReject', () => { + test('opened', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); + }); + + story('ToogleError', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + flaky: { + in: ['chrome2022', 'chrome2022Dark'], + tests: ['plain again', 'with error'], + }, + }, + }); + + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('with error', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: "[data-comp-name~='Toggle']" })) + .perform(); + await delay(200); + await this.expect(await this.takeScreenshot()).to.matchImage('with error'); + }); + + test('plain again', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: "[data-comp-name~='Toggle']" })) + .perform(); + await delay(200); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: "[data-comp-name~='Toggle']" })) + .perform(); + await delay(200); + await this.expect(await this.takeScreenshot()).to.matchImage('plain again'); + }); + }); + + story('WithExternalValue', () => { + test('initial value', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('initial value'); + }); + + test('reset value', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="resetBtn"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('reset value'); + }); + + test('set value', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="resetBtn"]' })) + .click(this.browser.findElement({ css: '[data-tid="setValueBtn"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('set value'); + }); + }); + + story('FocusFlow', () => { + test('before', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('before'); + }); + + test('after Enter on Item', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ENTER) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('after Enter on Item'); + }); + + test('after tab to the next field', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ENTER) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('after tab to the next field'); + }); + }); + + story('WithTooltip', () => { + test('show and hide Tooltip', async function () { + const body = await this.browser.findElement({ css: 'body' }); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid="InputLikeText__input"]' })) + .perform(); + await delay(1000); + const showTooltip = await body.takeScreenshot(); + await this.browser.actions({ bridge: true }).click(body).pause(1000).perform(); + const hideTooltip = await body.takeScreenshot(); + await this.expect({ showTooltip, hideTooltip }).to.matchImages(); + }); + }); + + story('MobileSimple', () => { + test('opened', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid="ComboBoxView__root"]' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('opened'); + }); + }); + + story('WithManualPosition', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } }, + }); + + test('opened top with portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened top with portal'); + }); + + test('opened bottom with portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) + .perform(); + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom with portal'); + }); + + test('opened top without portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="portal"]' })) + .perform(); + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened top without portal'); + }); + + test('opened bottom without portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="portal"]' })) + .perform(); + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) + .perform(); + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom without portal'); + }); + }); + + story('Size', () => { + test('clicked all', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="open-all"]' })) + .perform(); + await delay(500); + await this.browser.executeScript(function () { + const containers = document.querySelectorAll('[data-tid~="ScrollContainer__inner"]'); + for (let i = 0; i < containers.length; i++) { + containers[i].scrollTop += 300; + } + }); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('ClickedAll'); + }); + }); +}); diff --git a/packages/react-ui/components/ComboBox/__stories__/Combobox.stories.tsx b/packages/react-ui/components/ComboBox/__stories__/Combobox.stories.tsx new file mode 100644 index 00000000000..299548c5301 --- /dev/null +++ b/packages/react-ui/components/ComboBox/__stories__/Combobox.stories.tsx @@ -0,0 +1,913 @@ +// TODO: Rewrite stories and enable rule (in process of functional refactoring). +/* eslint-disable react/no-unstable-nested-components */ +import React from 'react'; +import { action } from '@storybook/addon-actions'; +import BabyIcon from '@skbkontur/react-icons/Baby'; +import SearchIcon from '@skbkontur/react-icons/Search'; + +import { Meta, Story } from '../../../typings/stories'; +import { ComboBox, ComboBoxProps } from '../ComboBox'; +import { MenuItem, MenuItemState } from '../../MenuItem'; +import { MenuSeparator } from '../../MenuSeparator'; +import { Nullable } from '../../../typings/utility-types'; +import { Toggle } from '../../Toggle'; +import { Button } from '../../Button'; +import { Gapped } from '../../Gapped'; +import { MenuHeader } from '../../MenuHeader'; +import { mergeRefs } from '../../../lib/utils'; +import { Tooltip } from '../../Tooltip'; +import { rootNode, TSetRootNode } from '../../../lib/rootNode'; + +// eslint-disable-next-line jest/no-mocks-import +const { getCities } = require('../__mocks__/getCities.js'); + +export default { title: 'ComboBox' } as Meta; + +export const SimpleComboboxStory: Story = () => ( +
+ +
+); +SimpleComboboxStory.storyName = 'simple combobox'; + +export const OpenToTop: Story = () => ( +
+ +
+); +OpenToTop.storyName = 'open to top'; + +export const AlwaysReject: Story = () => ( +
+ Promise.reject()} /> +
+); +AlwaysReject.storyName = 'always reject'; + +interface SampleState { + delay: number; +} +export const SimpleComboboxWithDelay = () => { + class Sample extends React.Component { + public state: SampleState = { + delay: 1000, + }; + public render() { + return ( +
+ +

+ +

+
+ ); + } + + private handleChangeDelay = (event: React.ChangeEvent) => { + const value = event.target.valueAsNumber; + + this.setState({ + delay: value, + }); + }; + } + + return ; +}; +SimpleComboboxWithDelay.storyName = 'simple combobox with delay'; +SimpleComboboxWithDelay.parameters = { creevey: { skip: true } }; + +export const WithErrorHandling = () => ( + +); +WithErrorHandling.storyName = 'with error handling'; +WithErrorHandling.parameters = { creevey: { skip: true } }; + +export const WithErrorSkipping = () => ( + +); +WithErrorSkipping.storyName = 'with error skipping'; +WithErrorSkipping.parameters = { creevey: { skip: true } }; + +export const WithWarning = () => ( + +); +WithWarning.storyName = 'with warning'; +WithWarning.parameters = { creevey: { skip: true } }; + +export const WithRejections = () => ; +WithRejections.storyName = 'with rejections'; +WithRejections.parameters = { creevey: { skip: true } }; + +export const Disabled = () => ; +Disabled.storyName = 'disabled'; +Disabled.parameters = { creevey: { skip: true } }; + +export const WithCustomElements = () => ( + // @ts-expect-error: Undocumented feature. + +); +WithCustomElements.storyName = 'with custom elements'; +WithCustomElements.parameters = { creevey: { skip: true } }; + +export const Autocomplete = () => ( + +); +Autocomplete.storyName = 'autocomplete'; +Autocomplete.parameters = { creevey: { skip: true } }; + +export const WithAutoFocus = () => ( +
+ +
+); +WithAutoFocus.storyName = 'with autoFocus'; + +export const WithAutoFocusAndAutocomplete = () => ( + +); +WithAutoFocusAndAutocomplete.storyName = 'with autoFocus and autocomplete'; +WithAutoFocusAndAutocomplete.parameters = { creevey: { skip: true } }; + +export const WithMaxMenuHeight = () => ; +WithMaxMenuHeight.storyName = 'with maxMenuHeight'; +WithMaxMenuHeight.parameters = { creevey: { skip: true } }; + +export const WithBorderless = () => ( + +); +WithBorderless.storyName = 'with borderless'; +WithBorderless.parameters = { creevey: { skip: true } }; + +export const WithCenterAlign = () => ; +WithCenterAlign.storyName = 'with center align'; +WithCenterAlign.parameters = { creevey: { skip: true } }; + +export const NotRenderNotFound = () => ( + null} /> +); +NotRenderNotFound.storyName = 'not render NotFound'; +NotRenderNotFound.parameters = { creevey: { skip: true } }; + +export const WithRightAlign = () => ; +WithRightAlign.storyName = 'with right align'; +WithRightAlign.parameters = { creevey: { skip: true } }; + +export const WithMaxLength = () => ; +WithMaxLength.storyName = 'with maxLength'; +WithMaxLength.parameters = { creevey: { skip: true } }; + +export const ToogleError: Story = () => ; +ToogleError.storyName = 'toogle error'; + +export const WithNullOnUnexpectedInput = () => ( + Promise.resolve([])} onUnexpectedInput={() => null} /> +); +WithNullOnUnexpectedInput.storyName = 'with `null` onUnexpectedInput'; +WithNullOnUnexpectedInput.parameters = { creevey: { skip: true } }; + +export const WithExternalValue: Story = () => ; +WithExternalValue.storyName = 'with external value'; + +export const WithRenderItemState = () => String(state)} />; +WithRenderItemState.storyName = 'with renderItem state'; +WithRenderItemState.parameters = { creevey: { skip: true } }; + +export const OpenCloseSearchMethods = () => { + let combobox: Nullable> = null; + return ( +
+ (combobox = e)} + value={items[0]} + getItems={search} + renderItem={(i) => i.name} + valueToString={(v) => v.name} + renderValue={(v) => v.name} + itemToValue={(v) => v.name} + />{' '} + + {' '} + {' '} + {' '} + {' '} + + +
+ ); +}; +OpenCloseSearchMethods.storyName = 'open, close, search methods'; +OpenCloseSearchMethods.parameters = { creevey: { skip: true } }; + +export const FocusFlow: Story = () => ( +
+ +
+
+ +
+); +FocusFlow.storyName = 'focus flow'; + +export const NestedComboBoxes = () => { + const RecursiveComboboxes = ({ depth }: { depth: number }) => ( +
+ {Array.from({ length: 2 }).map((_, i) => ( +
{depth > 1 ? : }
+ ))} +
+ ); + return ; +}; +NestedComboBoxes.storyName = '1024 nested ComboBoxes'; +NestedComboBoxes.parameters = { creevey: { skip: true } }; + +export const WithManyComplexMenuItems = () => ( +
+ +
+); +WithManyComplexMenuItems.storyName = 'with many complex menu items'; +WithManyComplexMenuItems.parameters = { creevey: { skip: true } }; + +export const WithAddButton = () => ( + query && alert(query)}>Добавить {query}} + /> +); +WithAddButton.storyName = 'with add button'; +WithAddButton.parameters = { creevey: { skip: true } }; + +interface ComboBoxWithErrorTogglerState { + value: { label: number }; + error: boolean; +} +class ComboBoxWithErrorToggler extends React.Component { + public state: ComboBoxWithErrorTogglerState = { + error: false, + value: { label: 0 }, + }; + + public render() { + return ( + <> + Promise.resolve([{ label: 0 }])} /> + + this.setState((state: ComboBoxWithErrorTogglerState) => ({ + error: value, + value: { label: state.value.label + 1 }, + })) + } + /> + + ); + } +} + +interface ValueType { + id: number; + name: string; +} + +interface ComboBoxState { + value: Nullable; + error: boolean; + warning: boolean; +} + +interface TestComboboxProps extends Omit, 'onUnexpectedInput' | 'getItems'> { + onSearch: (query: string) => Promise; + onUnexpectedInput?: (updateState: (newState: Pick) => void) => (x: string) => any; +} + +class TestComboBox extends React.Component, ComboBoxState> { + public static defaultProps = { + ...ComboBox.defaultProps, + onSearch: () => Promise.resolve([]), + }; + public state: ComboBoxState = { + value: null, + error: false, + warning: false, + }; + + private combobox: Nullable> = null; + + public render() { + return ( +
+ x.id} + disabled={this.props.disabled} + error={this.state.error} + warning={this.state.warning} + value={this.state.value} + maxMenuHeight={this.props.maxMenuHeight} + onBlur={action('blur')} + onFocus={() => this.setState({ error: false, warning: false }, action('focus'))} + getItems={this.props.onSearch} + renderItem={this.props.renderItem} + renderValue={renderValue} + renderAddButton={this.props.renderAddButton} + valueToString={(x) => x.name} + placeholder="numbers" + onValueChange={this.handleChange} + onUnexpectedInput={this.props.onUnexpectedInput ? this.props.onUnexpectedInput(this.updateState) : undefined} + totalCount={this.props.totalCount} + renderTotalCount={(found, total) => `Найдено ${found} из ${total}`} + ref={(el) => { + this.combobox = el; + }} + />{' '} + + {this.state.error &&
Необходимо выбрать значение
} + {this.state.warning &&
Вы не выбрали значение
} +
+ ); + } + + private updateState = (newState: Partial) => this.setState((state) => ({ ...state, ...newState })); + + private handleChange = (value: ValueType) => { + this.setState({ value, error: false }); + }; +} + +interface SimpleComboboxProps { + noInitialValue?: boolean; + delay?: number; +} + +interface SimpleComboboxState { + value: Nullable<{ value: number; label: string }>; +} + +interface ComboboxItem { + value: number; + label: string; +} + +@rootNode +class SimpleCombobox extends React.Component, SimpleComboboxState> { + public static defaultProps = { + ...ComboBox.defaultProps, + getItems: () => Promise.resolve([]), + }; + public state = { + value: this.props.noInitialValue ? null : { value: 1, label: 'First' }, + }; + private setRootNode!: TSetRootNode; + private comboBoxRef: React.RefObject = React.createRef(); + + public render() { + return ( + this.setState({ value })} + totalCount={this.props.renderTotalCount ? this.items.length + 1 : undefined} + renderTotalCount={this.props.renderTotalCount} + /> + ); + } + + public open() { + if (this.comboBoxRef.current) { + this.comboBoxRef.current.open(); + } + } + + public search(query?: string) { + if (this.comboBoxRef.current) { + this.comboBoxRef.current.search(query); + } + } + + private items: ComboboxItem[] = [ + { value: 1, label: 'First' }, + { value: 2, label: 'Second' }, + { value: 3, label: 'Third' }, + { value: 4, label: 'Fourth' }, + { value: 5, label: 'Fifth' }, + { value: 6, label: 'Sixth' }, + { value: 7, label: 'A long long long long long long time ago' }, + ]; + private getItems = (query: string) => + Promise.resolve( + this.items.filter((x) => x.label.toLowerCase().includes(query.toLowerCase()) || x.value.toString(10) === query), + ).then((result) => new Promise((ok) => setTimeout(ok, this.props.delay || 0, result))); +} + +interface ComplexComboboxItem { + value: number; + label: string; +} +interface City { + Id: number; + City: string; +} +interface ComboboxSearchResult { + foundItems: City[]; + totalCount: number; +} +type ComplexComboboxProps = Omit, 'getItems'>; +interface ComplexComboboxState { + value: Nullable; +} +class ComplexCombobox extends React.Component { + public static defaultProps = ComboBox.defaultProps; + public state: ComplexComboboxState = { + value: null, + }; + private popularItems: ComplexComboboxItem[] = [ + { value: 956, label: 'Махачкала' }, + { value: 4974, label: 'Верхняя-Пышма' }, + { value: 4980, label: 'Екатеринбург' }, + ]; + + public render() { + return ( + + ); + } + + private handleChange = (value: ComplexComboboxItem) => this.setState({ value }); + + private getItems = (query: string) => { + return getCities(query) + .then(({ foundItems, totalCount }: ComboboxSearchResult) => ({ + foundItems: foundItems.map(this.mapCity), + totalCount, + })) + .then(({ foundItems, totalCount }: { foundItems: ComplexComboboxItem[]; totalCount: number }) => ({ + popularItems: query.length === 0 ? this.popularItems : [], + itemsToShow: foundItems, + totalCount, + })) + .then( + ({ + popularItems, + itemsToShow, + totalCount, + }: { + popularItems: ComplexComboboxItem[]; + itemsToShow: ComplexComboboxItem[]; + totalCount: number; + }) => + ([] as unknown[]).concat( + popularItems, + popularItems.length ? (() as any) : [], + itemsToShow, + this.renderTotalCount(itemsToShow.length, totalCount), + ), + ); + }; + + private renderItem = (item: ComplexComboboxItem) => { + return item ? ( + +
{item.value}
+
{item.label}
+
+ ) : null; + }; + + private mapCity = ({ Id, City }: { Id: number; City: string }) => ({ + value: Id, + label: City, + }); + + private renderTotalCount = (foundCount: number, totalCount: number) => { + if (foundCount < totalCount) { + return ( + + Показано {foundCount} из {totalCount} найденных городов. + + ); + } + + return []; + }; +} + +function errorStrategy(setState: (state: Partial) => void): (x: any) => void { + return (x) => { + if (x) { + setState({ error: true }); + } + }; +} + +function nullStrategy(setState: (state: Partial) => void): (x: any) => void { + return (x) => { + if (x) { + setState({ value: null }); + } + }; +} + +function warningStrategy(setState: (state: Partial) => void): (x: any) => void { + return (x) => { + if (x) { + setState({ warning: true }); + } + }; +} + +const items: ValueType[] = [ + { id: 1, name: 'one' }, + { id: 2, name: 'two' }, + { id: 3, name: 'three' }, + { id: 4, name: 'four' }, + { id: 5, name: 'five' }, + { id: 6, name: 'six' }, + { id: 7, name: 'seven' }, + { id: 8, name: 'eight' }, + { id: 9, name: 'nine' }, + { id: 10, name: 'ten' }, + { id: 11, name: 'eleven' }, + { id: 12, name: 'twelve' }, + { id: 13, name: 'very long long long long long long name' }, + { id: 99, name: 'Putinka' }, +]; + +function search(query: string) { + return Promise.resolve(items.filter((x) => x.name.toLowerCase().indexOf(query.toLowerCase()) !== -1)); +} + +let searchCount = 0; +function searchWithRejections(query: string): Promise { + const random = (v: number) => Math.random() * v; + + const delay = (v: any) => new Promise((resolve) => setTimeout(resolve, random(5) * 100, v)); + + searchCount++; + return Promise.resolve() + .then(delay) + .then(() => { + if (searchCount % 2) { + throw new Error(); + } + return items.filter((x) => x.name.indexOf(query.toLowerCase()) !== -1); + }); +} + +function searchWithCustomElements(query: string) { + const _items = items.filter((x) => x.name.includes(query.toLowerCase())); + const disabled = Nothing was found; + return Promise.resolve([ + } disabled> + World + , + , + ..._items.slice(0, 3), + ...(_items.slice(0, 3).length ? [] : []), + ...(_items.slice(3).length ? _items.slice(3) : [disabled]), + , + alert('Clicked')}> + Ha ha + , + ]); +} + +function renderValue({ id, name }: ValueType): React.ReactNode { + return ( +
+ + {name} + + {id} +
+ ); +} + +interface ComboBoxWithExternalValueItem { + value: string; + label: string; +} +interface ComboBoxWithExternalValueState { + value: ComboBoxWithExternalValueItem; + warning: boolean; +} +class ComboBoxWithExternalValue extends React.Component { + public state: ComboBoxWithExternalValueState = { + value: { value: '1', label: 'First' }, + warning: false, + }; + + private combobox: Nullable>; + + public render = () => ( +
+ (this.combobox = element)} + /> + + +
+ this.state.value: {JSON.stringify(this.state.value)} +
+
+ ); + + private fill = () => { + this.setState({ + value: { value: '1', label: 'First' }, + warning: false, + }); + }; + + private reset = () => { + this.setState({ + warning: false, + value: null, + }); + if (this.combobox) { + this.combobox.reset(); + } + }; + + private getItems = (q: string) => + Promise.resolve( + [ + { value: '1', label: 'First' }, + { value: '2', label: 'Second' }, + ].filter((x) => x.label.toLowerCase().includes(q.toLowerCase()) || x.value === q), + ); + + private onChange = (value: { value: string; label: string }) => this.setState({ value, warning: false }); + + private onUnexpectedInput = () => { + this.setState({ + warning: true, + }); + return null; + }; +} + +export const WithLeftIcon = () => ( + + } searchOnFocus={false} autoFocus /> + } size="small" drawArrow={false} /> + } size="medium" drawArrow={false} /> + } size="large" drawArrow={false} /> + +); +WithLeftIcon.storyName = 'with left icon'; + +export const WithRightIcon = () => ( + + } searchOnFocus={false} autoFocus /> + } size="small" /> + } size="medium" /> + } size="large" /> + +); +WithRightIcon.storyName = 'with right icon'; + +export const WithTooltip: Story = () => { + return ( +
+ 'tooltip on focus'} trigger="focus" pos="right top"> + + +
+ ); +}; + +WithTooltip.storyName = 'with tooltip'; + +export const MobileSimple: Story = () => ( + <> + +
+ +
+ + query && ( + alert(query)}> + Добавить {query} + + ) + } + /> + +); +MobileSimple.storyName = 'mobile simple'; +MobileSimple.parameters = { + viewport: { + defaultViewport: 'iphone', + }, +}; + +export const WithManualPosition: Story = () => { + const [menuPos, setMenuPos] = React.useState<'top' | 'bottom'>('top'); + const [isPortalDisabled, setIsPortalDisabled] = React.useState(false); + + return ( +
+ + + +
+ ); +}; +WithManualPosition.storyName = 'with manual position'; + +export const WithExtendedItem: Story = () => { + const [value, setValue] = React.useState(); + + const CustomItem = ({ id, name }: ValueType) => ( + + CustomItem: {id} + {name} + + ); + + const RenderItem = ({ id, name, state = null }: ValueType & { state?: MenuItemState }) => ( + + RenderItem: {id} + {name} (state: {state}) + + ); + + const ItemWrapper = ({ id, name }: ValueType) => ( + + ItemWrapper: {id} + {name} + + ); + + return ( + <> + Пример передачи в getItems всех допустимых типов. +
+ Должны работать навигация клавишами и выбор пункта. +
+ + value={value} + onValueChange={setValue} + itemToValue={(item) => item.id} + renderValue={(item) => item.name} + valueToString={(item) => item.name} + getItems={() => + Promise.resolve([ + { id: 1, name: 'Paris' }, + { id: 2, name: 'Madrid' }, + , +
, + + + , + () => ( + + + + ), + { id: 5, name: 'Rome' }, + { id: 6, name: 'Amsterdam' }, + ]) + } + renderItem={(item, state) => } + itemWrapper={(item) => + function itemWrapper(props: React.PropsWithChildren) { + const isJust2Items = item.id === 5 || item.id === 6; + return ; + } + } + /> + + ); +}; +WithExtendedItem.parameters = { creevey: { skip: true } }; + +export const Size: Story = () => { + let small: SimpleCombobox | null = null; + let medium: SimpleCombobox | null = null; + let large: SimpleCombobox | null = null; + const handleClick = () => { + if (small) { + small.search(''); + small.open(); + } + if (medium) { + medium.search(''); + medium.open(); + } + if (large) { + large.search(''); + large.open(); + } + }; + return ( +
+ + + { + small = element; + }} + renderTotalCount={(foundCount: number, totalCount: number) => + `Показано ${foundCount} из ${totalCount} найденных элементов.` + } + /> + { + medium = element; + }} + renderTotalCount={(foundCount: number, totalCount: number) => + `Показано ${foundCount} из ${totalCount} найденных элементов.` + } + /> + { + large = element; + }} + renderTotalCount={(foundCount: number, totalCount: number) => + `Показано ${foundCount} из ${totalCount} найденных элементов.` + } + /> + +
+ ); +}; + +Size.storyName = 'size'; From af6b581b75ddd001ed7895113c37360deb1bcc55 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Wed, 8 May 2024 16:30:36 +0500 Subject: [PATCH 023/197] chore: fix CurrencyInput test --- .../__creevey__/CurrencyInput.creevey.ts | 118 ++++++++++ .../__stories__/CurrencyInput.stories.tsx | 202 ++++++++++++++++++ 2 files changed, 320 insertions(+) create mode 100644 packages/react-ui/components/CurrencyInput/__creevey__/CurrencyInput.creevey.ts create mode 100644 packages/react-ui/components/CurrencyInput/__stories__/CurrencyInput.stories.tsx diff --git a/packages/react-ui/components/CurrencyInput/__creevey__/CurrencyInput.creevey.ts b/packages/react-ui/components/CurrencyInput/__creevey__/CurrencyInput.creevey.ts new file mode 100644 index 00000000000..3f6e44db8d5 --- /dev/null +++ b/packages/react-ui/components/CurrencyInput/__creevey__/CurrencyInput.creevey.ts @@ -0,0 +1,118 @@ +import { story, kind, test } from 'creevey'; +import { delay } from '../../../lib/utils'; + +kind('CurrencyInput', () => { + story('SampleStory', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'flacky visible(?!) cursor': { + in: ['chromeDark'], + tests: ['Focus', 'Input value', 'External focus and input'], + }, + }, + }); + + test('Plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); + }); + + test('Focus', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click( + this.browser.findElement({ + css: '[data-comp-name*="CurrencyInput"] input', + }), + ) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('Focus'); + }); + + test('Input value', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click( + this.browser.findElement({ + css: '[data-comp-name*="CurrencyInput"] input', + }), + ) + .sendKeys('1') + .perform(); + await delay(500); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('2') + .perform(); + await delay(500); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('3') + .perform(); + await delay(500); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('4') + .perform(); + await delay(500); + await this.browser + .actions({ + bridge: true, + }) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('Input value'); + }); + + test('External focus and input', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="focus-input"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('1') + .perform(); + await delay(500); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('2') + .perform(); + await delay(500); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('3') + .perform(); + await delay(500); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('4') + .perform(); + await delay(500); + await this.browser + .actions({ + bridge: true, + }) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('External focus and input'); + }); + }); +}); diff --git a/packages/react-ui/components/CurrencyInput/__stories__/CurrencyInput.stories.tsx b/packages/react-ui/components/CurrencyInput/__stories__/CurrencyInput.stories.tsx new file mode 100644 index 00000000000..524bf6ccbc8 --- /dev/null +++ b/packages/react-ui/components/CurrencyInput/__stories__/CurrencyInput.stories.tsx @@ -0,0 +1,202 @@ +// TODO: Rewrite stories and enable rule (in process of functional refactoring). +/* eslint-disable react/no-unstable-nested-components */ +import React from 'react'; + +import { isNullable } from '../../../lib/utils'; +import { Meta, Story } from '../../../typings/stories'; +import { CurrencyInput, CurrencyInputProps } from '../CurrencyInput'; +import { Gapped } from '../../Gapped'; +import { Button } from '../../Button'; +import { Toggle } from '../../Toggle'; +import { Nullable } from '../../../typings/utility-types'; + +interface CurrencyInputDemoProps { + borderless?: boolean; +} +interface CurrencyInputDemoState { + // Intended behavior. CurrencyInput technically can't accept strings + // eslint-disable-next-line @typescript-eslint/no-explicit-any + value: any; + hideTrailingZeros: boolean; + fractionDigits: number; + signed: boolean; +} + +class CurrencyInputDemo extends React.Component { + public state: CurrencyInputDemoState = { + value: null, + signed: false, + hideTrailingZeros: false, + fractionDigits: 2, + }; + + public render() { + return ( + + + + + + + + + +
+ value: {this.formatValue(this.state.value)} +
+
+ signed: + +
+
+ trailing zeros: + +
+ +
+ digits: {this.formatValue(this.state.fractionDigits)} +
+
+ ); + } + + private handleChange = (value: Nullable) => { + this.setState({ value }); + }; + + private handleRand = () => { + const fraction = this.state.fractionDigits ?? 4; + const length = Math.min(15, 7 + fraction); + const rand = Math.floor(Math.random() * Math.pow(10, length)); + const value = rand / Math.pow(10, fraction); + this.setState({ value }); + }; + + private handleDigits = (event: React.ChangeEvent) => { + this.setState({ + value: null, + fractionDigits: event.target.value === '15' ? null : parseInt(event.target.value, 10), + }); + }; + + private handleSigned = (value: boolean) => { + this.setState({ + value: null, + signed: value, + }); + }; + + private handleHideTrailingZeros = (value: boolean) => { + this.setState({ + value: null, + hideTrailingZeros: value, + }); + }; + + private formatValue = (value: Nullable): string => { + return isNullable(value) ? 'null' : value.toString(); + }; +} + +interface SampleState { + value: Nullable; +} +class Sample extends React.Component> { + public state: SampleState = { + value: this.props.value, + }; + + private currencyInputElement: CurrencyInput | null = null; + + public render() { + return ( +
+ +
+ +
+
+ ); + } + + private handleChange = (value: Nullable) => { + this.setState({ value }); + }; + + private currencyInputRef = (element: CurrencyInput | null) => { + this.currencyInputElement = element; + }; + + private handleClickButton = () => { + if (this.currencyInputElement) { + this.currencyInputElement.focus(); + } + }; +} + +export default { title: 'CurrencyInput' } as Meta; + +export const Demo = () => ; +Demo.parameters = { creevey: { skip: true } }; +export const WithBorderless = () => ; +WithBorderless.storyName = 'With borderless'; +WithBorderless.parameters = { creevey: { skip: true } }; + +export const SampleStory: Story = () => ; +SampleStory.storyName = 'Sample'; + +export const ManualMount = () => { + class ManualMounting extends React.Component { + public state = { + mounted: false, + }; + + public render() { + return ( +
+ + {this.state.mounted && ( +
+ +
+ )} +
+ ); + } + + private handleChangeMounting = (event: React.ChangeEvent) => { + this.setState({ + mounted: event.target.checked, + }); + }; + } + return ; +}; +ManualMount.storyName = 'Manual mount'; +ManualMount.parameters = { creevey: { skip: true } }; From e81effe661bf08cab72016be477e63794746e12b Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Mon, 13 May 2024 10:37:08 +0500 Subject: [PATCH 024/197] chore: fix CurrencyLabel test --- .../__stories__/CurrencyLabel.stories.tsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 packages/react-ui/components/CurrencyLabel/__stories__/CurrencyLabel.stories.tsx diff --git a/packages/react-ui/components/CurrencyLabel/__stories__/CurrencyLabel.stories.tsx b/packages/react-ui/components/CurrencyLabel/__stories__/CurrencyLabel.stories.tsx new file mode 100644 index 00000000000..7c1c5993740 --- /dev/null +++ b/packages/react-ui/components/CurrencyLabel/__stories__/CurrencyLabel.stories.tsx @@ -0,0 +1,14 @@ +import React from 'react'; + +import { CurrencyLabel } from '../CurrencyLabel'; + +export default { title: 'CurrencyLabel' }; + +export const Simple = () => ; +Simple.storyName = 'simple'; + +export const WithCurrencySymbol = () => ; +WithCurrencySymbol.storyName = 'with currency symbol'; + +export const WithFractionDigits = () => ; +WithFractionDigits.storyName = 'with fraction digits'; From 04fa17c18e7552b6cd3b0b123fdb5e445f0b2f0c Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Mon, 13 May 2024 11:07:08 +0500 Subject: [PATCH 025/197] chore: rename static method in Select --- packages/react-ui/components/Select/Select.md | 12 +++++++----- packages/react-ui/components/Select/Select.tsx | 6 +++--- .../components/Select/__tests__/Select-test.tsx | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/react-ui/components/Select/Select.md b/packages/react-ui/components/Select/Select.md index cd454d0a44e..1fc34b83825 100644 --- a/packages/react-ui/components/Select/Select.md +++ b/packages/react-ui/components/Select/Select.md @@ -3,9 +3,10 @@ ```jsx harmony const [value, setValue] = React.useState(); -const items = [Select.static(() => Not selectable), 'One', 'Two', 'Three', Select.SEP, 'Four']; +const items = [Select.staticElement(() => Not + selectable), 'One', 'Two', 'Three', Select.SEP, 'Four']; -; ``` @@ -47,17 +48,18 @@ const items = ['One', 'Two', 'Three', Select.SEP, 'Four']; Пример использования пропа `_renderButton`: ```jsx harmony -import { Link } from '@skbkontur/react-ui'; +import {Link} from '@skbkontur/react-ui'; import PeopleIcon from '@skbkontur/react-icons/People'; const [value, setValue] = React.useState(); -const items = [Select.static(() => Not selectable), 'One', 'Two', 'Three', Select.SEP, 'Four']; +const items = [Select.staticElement(() => Not + selectable), 'One', 'Two', 'Three', Select.SEP, 'Four']; const renderLinkButton = params => { const linkProps = { disabled: params.disabled, - icon: , + icon: , _button: true, _buttonOpened: params.opened, diff --git a/packages/react-ui/components/Select/Select.tsx b/packages/react-ui/components/Select/Select.tsx index 0e06e724a8f..6d40d32b1c8 100644 --- a/packages/react-ui/components/Select/Select.tsx +++ b/packages/react-ui/components/Select/Select.tsx @@ -122,7 +122,7 @@ export interface SelectProps * Вставить невыделяемый элемент со своей разметкой можно так: * ``` * {itemsObject.second}), + Select.staticElement(() => {itemsObject.second}), itemsObject.third, +itemsObject.fourth, Select.SEP, From ed0d74408e66f32eec918f6bf3ae6bdd13bf1e1e Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Mon, 13 May 2024 11:07:40 +0500 Subject: [PATCH 026/197] chore: fix DateInput test --- .../__creevey__/DateInput.creevey.ts | 154 +++++++++ .../__stories__/DateInput.stories.tsx | 319 ++++++++++++++++++ 2 files changed, 473 insertions(+) create mode 100644 packages/react-ui/components/DateInput/__creevey__/DateInput.creevey.ts create mode 100644 packages/react-ui/components/DateInput/__stories__/DateInput.stories.tsx diff --git a/packages/react-ui/components/DateInput/__creevey__/DateInput.creevey.ts b/packages/react-ui/components/DateInput/__creevey__/DateInput.creevey.ts new file mode 100644 index 00000000000..6bcee12b490 --- /dev/null +++ b/packages/react-ui/components/DateInput/__creevey__/DateInput.creevey.ts @@ -0,0 +1,154 @@ +import { story, kind, test } from 'creevey'; +import { delay } from '../../../lib/utils'; + +kind('DateInput', () => { + story('Simple', () => { + test('idle', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('idle'); + }); + + test('focus', async function () { + await this.browser.executeScript(function () { + const input = window.document.querySelector("[data-comp-name~='DateInput']"); + if (input instanceof HTMLElement) { + input.focus(); + } + }); + await this.expect(await this.takeScreenshot()).to.matchImage('focus'); + }); + }); + + story('Disabled', () => { + test('idle', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('idle'); + }); + + test('focus', async function () { + await this.browser.executeScript(function () { + const input = window.document.querySelector("[data-comp-name~='DateInput']"); + if (input instanceof HTMLElement) { + input.focus(); + } + }); + await this.expect(await this.takeScreenshot()).to.matchImage('focus'); + }); + }); + + story('WithWidth', () => { + test('idle', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('idle'); + }); + + test('focus', async function () { + await this.browser.executeScript(function () { + const input = window.document.querySelector("[data-comp-name~='DateInput']"); + if (input instanceof HTMLElement) { + input.focus(); + } + }); + await this.expect(await this.takeScreenshot()).to.matchImage('focus'); + }); + }); + + story('BlurAlwaysAfterChange', () => { + test('value not changed', async function () { + await this.browser.executeScript(function () { + const input = window.document.querySelector("[data-comp-name~='DateInput']"); + if (input instanceof HTMLElement) { + input.focus(); + } + }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'body' })) + .perform(); + await delay(500); + await this.expect(await this.takeScreenshot()).to.matchImage('value not changed'); + }); + + test('value changed', async function () { + await this.browser.executeScript(function () { + const input = window.document.querySelector("[data-comp-name~='DateInput']"); + if (input instanceof HTMLElement) { + input.focus(); + } + }); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('12') + .click(this.browser.findElement({ css: 'body' })) + .perform(); + await delay(500); + await this.expect(await this.takeScreenshot()).to.matchImage('value changed'); + }); + + test('value restored', async function () { + await this.browser.executeScript(function () { + const input = window.document.querySelector("[data-comp-name~='DateInput']"); + if (input instanceof HTMLElement) { + input.focus(); + } + }); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.DELETE) + .click(this.browser.findElement({ css: 'body' })) + .perform(); + await this.browser.executeScript(function () { + const input = window.document.querySelector("[data-comp-name~='DateInput']"); + if (input instanceof HTMLElement) { + input.blur(); + } + }); + await this.expect(await this.takeScreenshot()).to.matchImage('value restored'); + }); + }); + + story('WithNoValue', () => { + test('idle', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage(); + }); + + test('focused', async function () { + await this.browser.executeScript(function () { + const input = window.document.querySelector("[data-comp-name~='DateInput']"); + if (input instanceof HTMLElement) { + input.focus(); + } + }); + await this.expect(await this.takeScreenshot()).to.matchImage(); + }); + }); + + story('WithError', () => { + test('focused', async function () { + const plain = await this.takeScreenshot(); + const DateInputPlaceholder = this.browser.findElement({ + css: '[data-tid~="DateFragmentsView__placeholder"]', + }); + await this.browser.actions({ bridge: true }).click(DateInputPlaceholder).perform(); + await delay(1000); + const focused = await this.takeScreenshot(); + await this.expect([plain, focused]).to.matchImages(); + }); + }); + + story('ShouldSetFocusOnPlaceholderClick', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'chrome only': { in: /^(?!\bchrome\b)/ } } }); + + test('focused', async function () { + const DateInputPlaceholder = this.browser.findElement({ + css: '[data-tid~="DateFragmentsView__placeholder"]', + }); + await this.browser.actions({ bridge: true }).click(DateInputPlaceholder).perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage(); + }); + }); +}); diff --git a/packages/react-ui/components/DateInput/__stories__/DateInput.stories.tsx b/packages/react-ui/components/DateInput/__stories__/DateInput.stories.tsx new file mode 100644 index 00000000000..b428e38c7ba --- /dev/null +++ b/packages/react-ui/components/DateInput/__stories__/DateInput.stories.tsx @@ -0,0 +1,319 @@ +import React from 'react'; +import { action } from '@storybook/addon-actions'; + +import { Meta, Story } from '../../../typings/stories'; +import { InternalDateOrder, InternalDateSeparator } from '../../../lib/date/types'; +import { Gapped } from '../../Gapped'; +import { Select } from '../../Select'; +import { DateInput, DateInputProps } from '../DateInput'; +import { LangCodes, LocaleContext } from '../../../lib/locale'; +import { defaultLangCode } from '../../../lib/locale/constants'; +import { InternalDateGetter } from '../../../lib/date/InternalDateGetter'; + +interface DateInputFormattingState { + order: InternalDateOrder; + separator: keyof typeof InternalDateSeparator; + value: string; +} +class DateInputFormatting extends React.Component { + public state: DateInputFormattingState = { + order: InternalDateOrder.YMD, + separator: 'Dot', + value: '21.12.2012', + }; + + public handleChangeOrder = (order: any) => this.setState({ order }); + public handleChangeSeparator = (separator: any) => this.setState({ separator }); + public handleChangeValue = (value: any) => { + action('change')(value); + this.setState({ value }); + }; + + public render() { + return ( + +
+ + Порядок компонентов InternalDateOrder + + +
+ + +
+
+
+
+ ); + } +} + +class DateInputDifferentFormatting extends React.Component { + public render() { + const value = '21.12.2012'; + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
YMDMDYDMY
Dot + + + + + + + + + + + +
Dash + + + + + + + + + + + +
Slash + + + + + + + + + + + +
Space + + + + + + + + + + + +
+ ); + } +} + +interface DateInputSimpleProps extends Partial { + defaultValue?: string; +} +interface DateInputSimpleState { + value: string; +} + +class DateInputSimple extends React.Component { + public state: DateInputSimpleState = { + value: this.props.defaultValue || '', + }; + + public handleChange = (value: string) => { + this.setState({ value }); + if (this.props.onValueChange) { + this.props.onValueChange(value); + } + }; + + public render() { + return ; + } +} + +class DateInputLastEvent extends React.Component { + private getTodayComponents = InternalDateGetter.getTodayComponents; + public state = { + lastEvent: 'none', + }; + + public handleFocus = () => { + InternalDateGetter.getTodayComponents = () => ({ + date: 1, + month: 1, + year: 2000, + }); + }; + + public handleBlur = () => { + InternalDateGetter.getTodayComponents = this.getTodayComponents; + this.setState({ lastEvent: 'blur' }); + }; + + public handleChange = () => { + this.setState({ lastEvent: 'change' }); + }; + + public render() { + return ( + + +
{this.state.lastEvent}
+
+ ); + } +} + +export default { title: 'DateInput' } as Meta; + +export const Simple: Story = () => ; +Simple.storyName = 'simple'; + +export const WithAutoFocus: Story = () => ; +WithAutoFocus.storyName = 'with autoFocus'; + +export const Formatting = () => ; +Formatting.storyName = 'formatting'; +Formatting.parameters = { creevey: { skip: true } }; + +export const DifferentFormatting = () => ; +DifferentFormatting.storyName = 'different formatting'; + +export const Disabled: Story = () => ; +Disabled.storyName = 'disabled'; + +export const WithWidth: Story = () => ; +WithWidth.storyName = 'with width'; + +export const BlurAlwaysAfterChange: Story = () => ; +BlurAlwaysAfterChange.storyName = 'blur always after change'; + +export const WithNoValue: Story = () => ; + +export const WithError: Story = () => ( + + + Error + + + Error and Disabled + + +); + +export const ShouldSetFocusOnPlaceholderClick: Story = () => { + return ; +}; +ShouldSetFocusOnPlaceholderClick.storyName = 'should set focus on placeholder click'; From 709b0bd58ffacf7f463c073d1c6e3399f969e937 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Mon, 13 May 2024 11:20:06 +0500 Subject: [PATCH 027/197] chore: fix DatePicker test --- .../__creevey__/DatePicker.creevey.ts | 188 +++++++++++ .../__stories__/DatePicker.stories.tsx | 301 ++++++++++++++++++ 2 files changed, 489 insertions(+) create mode 100644 packages/react-ui/components/DatePicker/__creevey__/DatePicker.creevey.ts create mode 100644 packages/react-ui/components/DatePicker/__stories__/DatePicker.stories.tsx diff --git a/packages/react-ui/components/DatePicker/__creevey__/DatePicker.creevey.ts b/packages/react-ui/components/DatePicker/__creevey__/DatePicker.creevey.ts new file mode 100644 index 00000000000..35a74a0eddf --- /dev/null +++ b/packages/react-ui/components/DatePicker/__creevey__/DatePicker.creevey.ts @@ -0,0 +1,188 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('DatePicker', () => { + story('WithMouseeventHandlers', () => { + test('opened', async function () { + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); + + test('DateSelect month', async function () { + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .perform(); + await delay(1000); + await this.browser + .actions({ bridge: true }) + .click( + this.browser.findElement({ + css: '[data-tid="MonthView__month"]:first-child [data-tid="MonthView__headerMonth"] [data-tid="DateSelect__caption"]', + }), + ) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('DateSelect month'); + }); + + test('DateSelect year', async function () { + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .perform(); + await delay(1000); + await this.browser + .actions({ bridge: true }) + .click( + this.browser.findElement({ + css: '[data-comp-name~="MonthView"]:first-child [data-tid="MonthView__headerYear"] [data-tid="DateSelect__caption"]', + }), + ) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('DateSelect year'); + }); + }); + + story('DatePickerWithMinMaxDate', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + flaky: { + in: /^(?!\b(chrome|ie11)\b)/, + tests: ['DateSelect months', 'DateSelect years'], + }, + }, + }); + + test('DateSelect months', async function () { + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .pause(1000) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .click( + this.browser.findElement({ + css: '[data-tid="MonthView__month"]:first-child [data-tid="MonthView__headerMonth"] [data-tid="DateSelect__caption"]', + }), + ) + .pause(1000) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('DateSelect months'); + }); + + test('DateSelect years', async function () { + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .pause(1000) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .click( + this.browser.findElement({ + css: '[data-comp-name~="MonthView"]:first-child [data-tid="MonthView__headerYear"] [data-tid="DateSelect__caption"]', + }), + ) + .pause(1000) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('DateSelect years'); + }); + }); + + story('DatePickerInRelativeBody', () => { + test('opened', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="toggle-relative-position"]' })) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); + }); + + story('WithManualPosition', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } } }); + + test('opened top without relative position', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened top without relative position'); + }); + + test('opened bottom without relative position', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom without relative position'); + }); + + test('opened top with relative position', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="relative"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened top with relative position'); + }); + + test('opened bottom with relative position', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-tid~="relative"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom'); + }); + }); +}); diff --git a/packages/react-ui/components/DatePicker/__stories__/DatePicker.stories.tsx b/packages/react-ui/components/DatePicker/__stories__/DatePicker.stories.tsx new file mode 100644 index 00000000000..d047c3888d3 --- /dev/null +++ b/packages/react-ui/components/DatePicker/__stories__/DatePicker.stories.tsx @@ -0,0 +1,301 @@ +import { action } from '@storybook/addon-actions'; +import React, { useCallback, useState, useEffect } from 'react'; + +import { Nullable } from '../../../typings/utility-types'; +import { Meta, Story } from '../../../typings/stories'; +import { InternalDateOrder, InternalDateSeparator } from '../../../lib/date/types'; +import { Button } from '../../Button'; +import { Gapped } from '../../Gapped'; +import { Tooltip } from '../../Tooltip'; +import { DatePicker } from '../DatePicker'; +import { LocaleContext, LangCodes } from '../../../lib/locale'; +import { emptyHandler } from '../../../lib/utils'; +import { SizeProp } from '../../../lib/types/props'; + +interface DatePickerWithErrorProps { + disabled?: boolean; + size?: SizeProp; +} +interface DatePickerWithErrorState { + tooltip: boolean; + value: Nullable; + error?: boolean; +} +class DatePickerWithError extends React.Component { + public state: DatePickerWithErrorState = { + value: '15.08.2014', + error: false, + tooltip: false, + }; + + public render() { + return ( + + 'Такой даты не существует'} + onCloseClick={this.removeTooltip} + > + + + + + + + + + + ); + } + + private handleChange = (value: any) => { + action('change')(value); + this.setState({ value }); + }; + + private invalidate = () => { + this.setState({ error: false, tooltip: false }); + }; + + private validate = () => { + const currentValue = this.state.value; + this.setState(() => { + const error = + !!currentValue && !DatePicker.validate(currentValue, { minDate: '08.15.2003', maxDate: '10.21.2006' }); + return { + error, + tooltip: error, + }; + }); + }; + + private removeTooltip = () => { + this.setState({ + tooltip: false, + }); + }; +} + +export default { + title: 'DatePicker', +} as Meta; + +export const WithMouseeventHandlers: Story = () => { + const [date, setDate] = useState('02.07.2017'); + + return ( +
+ console.count('enter')} + onMouseLeave={() => console.count('leave')} + onValueChange={setDate} + /> +
+ ); +}; +WithMouseeventHandlers.storyName = 'with mouseevent handlers'; + +export const WithMobileNativeDatePicker = () => { + const [date, setDate] = useState('02.07.2017'); + + return ( +
+ + With mobile native datepicker + console.count('enter')} + onMouseLeave={() => console.count('leave')} + onValueChange={(date) => { + setDate(date); + }} + useMobileNativeDatePicker + /> + +
+ ); +}; +WithMobileNativeDatePicker.storyName = 'with native datepickers on mobile devices'; +WithMobileNativeDatePicker.parameters = { creevey: { skip: true } }; + +export const WithAutoFocus = () => ( + +); +WithAutoFocus.storyName = 'with autoFocus'; +WithAutoFocus.parameters = { creevey: { skip: true } }; + +export const DatePickerWithErrorStory = () => ; +DatePickerWithErrorStory.storyName = 'DatePickerWithError'; +DatePickerWithErrorStory.parameters = { creevey: { skip: true } }; + +export const DatePickerDisabled = () => ; +DatePickerDisabled.storyName = 'DatePicker disabled'; +DatePickerDisabled.parameters = { creevey: { skip: true } }; + +export const DifferentSizes = () => ( + + void 0} /> + void 0} size="medium" /> + void 0} size="large" /> + +); + +interface DatePickerWithMinMaxState { + value: Nullable; + minDate: string; + maxDate: string; + order: InternalDateOrder; + separator: InternalDateSeparator; +} + +class DatePickerWithMinMax extends React.Component { + public state: DatePickerWithMinMaxState = { + minDate: '02.07.2017', + maxDate: '30.01.2020', + value: '02.07.2017', + order: InternalDateOrder.DMY, + separator: InternalDateSeparator.Dot, + }; + + public render(): React.ReactNode { + return ( + + + + + + + + ); + } +} + +export const DatePickerWithMinMaxDate: Story = () => ( +
+ +
+); +DatePickerWithMinMaxDate.storyName = 'DatePicker with min max date'; + +export const DatePickerLocaleProvider = () => { + return ( +
+ + + +
+ ); +}; +DatePickerLocaleProvider.storyName = 'DatePicker LocaleProvider'; +DatePickerLocaleProvider.parameters = { creevey: { skip: true } }; + +export const DatePickerInRelativeBody: Story = () => { + const [isRelative, toggleIsRelative] = useState(false); + const relativeClassName = 'relative'; + + const onClick = useCallback(() => { + toggleIsRelative(!isRelative); + document.querySelector('html')?.classList.toggle(relativeClassName); + }, [isRelative]); + const paddingTop = document.documentElement.clientHeight - 32 * 3; + + useEffect(() => { + return () => { + document.querySelector('html')?.classList.remove(relativeClassName); + }; + }, [relativeClassName]); + + return ( + <> + +
+ +
+ + ); +}; +DatePickerInRelativeBody.storyName = 'DatePicker In Relative Body'; + +export const WithManualPosition: Story = () => { + const [menuPos, setMenuPos] = useState<'top' | 'bottom'>('top'); + const [isRelative, toggleIsRelative] = useState(false); + const relativeClassName = 'relative'; + + const onClick = useCallback(() => { + toggleIsRelative(!isRelative); + document.querySelector('html')?.classList.toggle(relativeClassName); + }, [isRelative]); + + useEffect(() => { + return () => { + document.querySelector('html')?.classList.remove(relativeClassName); + }; + }, [relativeClassName]); + + return ( +
+ + + +
+ ); +}; +WithManualPosition.storyName = 'with manual position'; From 0fe7a1bbfb451895973d51af4f716dc78fbd0938 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Mon, 13 May 2024 11:25:35 +0500 Subject: [PATCH 028/197] chore: fix Dropdown test --- .../Dropdown/__creevey__/Dropdown.creevey.ts | 187 ++++++++++++++++++ .../Dropdown/__stories__/Dropdown.stories.tsx | 176 +++++++++++++++++ 2 files changed, 363 insertions(+) create mode 100644 packages/react-ui/components/Dropdown/__creevey__/Dropdown.creevey.ts create mode 100644 packages/react-ui/components/Dropdown/__stories__/Dropdown.stories.tsx diff --git a/packages/react-ui/components/Dropdown/__creevey__/Dropdown.creevey.ts b/packages/react-ui/components/Dropdown/__creevey__/Dropdown.creevey.ts new file mode 100644 index 00000000000..ea3d8256d70 --- /dev/null +++ b/packages/react-ui/components/Dropdown/__creevey__/Dropdown.creevey.ts @@ -0,0 +1,187 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('Dropdown', () => { + story('SimpleDropdown', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'MenuItem hover' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['MenuItem hover'] }, + }, + }); + + test('idle', async function () { + const element = await this.browser.findElement({ css: '.dropdown-test-container' }); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('idle'); + }); + + test('clicked', async function () { + const element = await this.browser.findElement({ css: '.dropdown-test-container' }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('clicked'); + }); + + test('MenuItem hover', async function () { + const element = await this.browser.findElement({ css: '.dropdown-test-container' }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' }), + }) + .perform(); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('MenuItem hover'); + }); + + test('selected item', async function () { + const element = await this.browser.findElement({ css: '.dropdown-test-container' }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' })) + .perform(); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('selected item'); + }); + }); + + story('WithMenuItemIcon', ({ setStoryParameters }) => { + setStoryParameters({ captureElement: '.dropdown-test-container' }); + + test('clicked', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); + }); + }); + + story('InsideScrollableContainer', ({ setStoryParameters }) => { + setStoryParameters({ captureElement: '.dropdown-test-container' }); + + test('scrolled', async function () { + await this.browser + .actions() + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + const opened = await this.takeScreenshot(); + await this.browser.executeScript(function () { + const scrollContainer = window.document.querySelector('.dropdown-test-container') as HTMLElement; + scrollContainer.scrollTop = scrollContainer.scrollHeight; + }); + const scrolled = await this.takeScreenshot(); + await this.expect({ opened, scrolled }).to.matchImages(); + }); + }); + + story('WithCustomSelectTheme', () => { + test('clicked', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); + }); + }); + + story('WithManualPosition', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } } }); + + test('opened top with portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened top with portal'); + }); + + test('opened bottom with portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom with portal'); + }); + + test('opened top without portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="portal"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened top without portal'); + }); + + test('opened bottom without portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="portal"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom without portal'); + }); + }); + + story('Size', () => { + test('clicked all', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="open-all"]' })) + .pause(500) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('ClickedAll'); + }); + }); +}); diff --git a/packages/react-ui/components/Dropdown/__stories__/Dropdown.stories.tsx b/packages/react-ui/components/Dropdown/__stories__/Dropdown.stories.tsx new file mode 100644 index 00000000000..a4b07f9d462 --- /dev/null +++ b/packages/react-ui/components/Dropdown/__stories__/Dropdown.stories.tsx @@ -0,0 +1,176 @@ +import React from 'react'; +import AddIcon from '@skbkontur/react-icons/Add'; +import BabyIcon from '@skbkontur/react-icons/Baby'; + +import { Button } from '../../Button'; +import { ThemeContext } from '../../../lib/theming/ThemeContext'; +import { ThemeFactory } from '../../../lib/theming/ThemeFactory'; +import { Meta, Story } from '../../../typings/stories'; +import { Dropdown } from '../Dropdown'; +import { MenuItem } from '../../MenuItem'; +import { Gapped } from '../../Gapped'; +import { MenuHeader } from '../../MenuHeader'; + +export default { + title: 'Dropdown', + decorators: [ + (Story: () => JSX.Element) => ( +
+ +
+ ), + ], +} as Meta; + +export const SimpleDropdown: Story = () => ( + + Menu item + +); + +export const WithFixedWidth: Story = () => ( + + Menu item + +); +WithFixedWidth.storyName = 'With fixed width'; +WithFixedWidth.parameters = { creevey: { captureElement: '.dropdown-test-container' } }; + +export const WithOverflow = () => ( + + Menu item + +); +WithOverflow.storyName = 'With overflow'; +WithOverflow.parameters = { creevey: { captureElement: '.dropdown-test-container' } }; + +export const WithIcon = () => ( + }> + Menu item + +); +WithIcon.storyName = 'With icon'; +WithIcon.parameters = { creevey: { captureElement: '.dropdown-test-container' } }; + +export const WithMenuItemIcon: Story = () => ( + }> + }>Menu item + Another item + +); +WithMenuItemIcon.storyName = 'With MenuItem icon'; + +export const WithIconAndOverflow = () => ( + } caption="Lorem ipsum dollar all mubarak ibn ahmed" width="100px"> + Menu item + +); +WithIconAndOverflow.storyName = 'With icon and overflow'; +WithIconAndOverflow.parameters = { creevey: { captureElement: '.dropdown-test-container' } }; + +export const InsideScrollableContainer: Story = () => ( +
+
+ + Menu item + +
+
+); + +export const WithCustomSelectTheme: Story = () => { + return ( + + {(theme) => { + return ( + + + + + + ); + }} + + ); +}; +WithCustomSelectTheme.storyName = 'with custom select theme'; + +export const WithManualPosition: Story = () => { + const [menuPos, setMenuPos] = React.useState<'top' | 'bottom'>('top'); + const [isPortalDisabled, setIsPortalDisabled] = React.useState(false); + + return ( +
+ + Menu item + + + +
+ ); +}; +WithManualPosition.storyName = 'with manual position'; + +export const Size: Story = () => { + const items = [one, 'two', three]; + let small: Dropdown | null = null; + let medium: Dropdown | null = null; + let large: Dropdown | null = null; + const handleClick = () => { + if (small) { + small.open(); + } + if (medium) { + medium.open(); + } + if (large) { + large.open(); + } + }; + return ( +
+ + + { + small = element; + }} + > + This is header + {items} + + { + medium = element; + }} + > + This is header + {items} + + { + large = element; + }} + > + This is header + {items} + + +
+ ); +}; +Size.storyName = 'size'; From d7fc51de6afdb762fe2fe4b4eccaee8131958ccf Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Mon, 13 May 2024 16:20:00 +0500 Subject: [PATCH 029/197] chore: fix DropdownMenu test --- .../opened/chrome/opened.png | 0 .../opened/chrome/opened.png | 0 .../navigate/chrome/arrowDown.png | 0 .../navigate/chrome/enter.png | 0 .../__creevey__/DropdownMenu.creevey.ts | 262 +++++++++++++ .../__stories__/DropdownMenu.stories.tsx | 344 ++++++++++++++++++ 6 files changed, 606 insertions(+) rename packages/react-ui/.creevey/images/DropdownMenu/{Functional tests => }/With Items And Icons Without Text Alignment/opened/chrome/opened.png (100%) rename packages/react-ui/.creevey/images/DropdownMenu/{Functional tests => }/With Items And Icons/opened/chrome/opened.png (100%) rename packages/react-ui/.creevey/images/DropdownMenu/{Functional tests => }/With nested menu items/navigate/chrome/arrowDown.png (100%) rename packages/react-ui/.creevey/images/DropdownMenu/{Functional tests => }/With nested menu items/navigate/chrome/enter.png (100%) create mode 100644 packages/react-ui/components/DropdownMenu/__creevey__/DropdownMenu.creevey.ts create mode 100644 packages/react-ui/components/DropdownMenu/__stories__/DropdownMenu.stories.tsx diff --git a/packages/react-ui/.creevey/images/DropdownMenu/Functional tests/With Items And Icons Without Text Alignment/opened/chrome/opened.png b/packages/react-ui/.creevey/images/DropdownMenu/With Items And Icons Without Text Alignment/opened/chrome/opened.png similarity index 100% rename from packages/react-ui/.creevey/images/DropdownMenu/Functional tests/With Items And Icons Without Text Alignment/opened/chrome/opened.png rename to packages/react-ui/.creevey/images/DropdownMenu/With Items And Icons Without Text Alignment/opened/chrome/opened.png diff --git a/packages/react-ui/.creevey/images/DropdownMenu/Functional tests/With Items And Icons/opened/chrome/opened.png b/packages/react-ui/.creevey/images/DropdownMenu/With Items And Icons/opened/chrome/opened.png similarity index 100% rename from packages/react-ui/.creevey/images/DropdownMenu/Functional tests/With Items And Icons/opened/chrome/opened.png rename to packages/react-ui/.creevey/images/DropdownMenu/With Items And Icons/opened/chrome/opened.png diff --git a/packages/react-ui/.creevey/images/DropdownMenu/Functional tests/With nested menu items/navigate/chrome/arrowDown.png b/packages/react-ui/.creevey/images/DropdownMenu/With nested menu items/navigate/chrome/arrowDown.png similarity index 100% rename from packages/react-ui/.creevey/images/DropdownMenu/Functional tests/With nested menu items/navigate/chrome/arrowDown.png rename to packages/react-ui/.creevey/images/DropdownMenu/With nested menu items/navigate/chrome/arrowDown.png diff --git a/packages/react-ui/.creevey/images/DropdownMenu/Functional tests/With nested menu items/navigate/chrome/enter.png b/packages/react-ui/.creevey/images/DropdownMenu/With nested menu items/navigate/chrome/enter.png similarity index 100% rename from packages/react-ui/.creevey/images/DropdownMenu/Functional tests/With nested menu items/navigate/chrome/enter.png rename to packages/react-ui/.creevey/images/DropdownMenu/With nested menu items/navigate/chrome/enter.png diff --git a/packages/react-ui/components/DropdownMenu/__creevey__/DropdownMenu.creevey.ts b/packages/react-ui/components/DropdownMenu/__creevey__/DropdownMenu.creevey.ts new file mode 100644 index 00000000000..96a1b8a8e38 --- /dev/null +++ b/packages/react-ui/components/DropdownMenu/__creevey__/DropdownMenu.creevey.ts @@ -0,0 +1,262 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +const outOfViewTests = (side: 'left' | 'right') => { + test('out of viewport', async function () { + if (side === 'left') { + await this.browser.executeScript(function () { + const container = window.document.querySelector('[data-tid="container"]') as HTMLElement; + container.scrollLeft = container.scrollWidth; + }); + } + + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="firstMenu"]' })) + .perform(); + await delay(1000); + + await this.expect(await this.takeScreenshot()).to.matchImage('out of viewport'); + }); + + test('out of edge with min menu width', async function () { + if (side === 'left') { + await this.browser.executeScript(function () { + const container = window.document.querySelector('[data-tid="container"]') as HTMLElement; + container.scrollLeft = container.scrollWidth; + }); + } + + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="secondMenu"]' })) + .perform(); + await delay(1000); + + await this.expect(await this.takeScreenshot()).to.matchImage('out of viewport with min menu width'); + }); +}; + +const textAlignmentTests = () => { + test('opened', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); +}; + +const navigateInNestedMenuItems = () => { + test('navigate', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) + .sendKeys(this.keys.DOWN) + .sendKeys(this.keys.DOWN) + .perform(); + const arrowDown = await this.browser.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ENTER) + .perform(); + await delay(1000); + const enter = await this.browser.takeScreenshot(); + await this.expect({ arrowDown, enter }).to.matchImages(); + }); +}; + +kind('DropdownMenu', () => { + story('SimpleExample', () => { + test('plain', async function () { + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('clickAfterClickedOnCaption', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('clickAfterClickedOnCaption'); + }); + + test('clicked', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); + }); + + test('tabPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); + }); + + test('enterPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ENTER) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('enterPress'); + }); + + test('escapePress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ENTER) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ESCAPE) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('escapePress'); + }); + }); + + story('CaptionWidth', () => { + test('plain', async function () { + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + }); + + story('WithHeaderAndFooter', () => { + test('clicked', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('clicked'); + }); + + test('scrolled by 100', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) + .perform(); + await this.browser.executeScript(function () { + const scrollContainer = window.document.querySelector('[data-tid~="ScrollContainer__inner"]') as HTMLElement; + scrollContainer.scrollTop += 100; + }); + await delay(2000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('scrolled by 100'); + }); + + test('scrolled down to bottom', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) + .perform(); + await this.browser.executeScript(function () { + const scrollContainer = window.document.querySelector('[data-tid~="ScrollContainer__inner"]') as HTMLElement; + scrollContainer.scrollTop += scrollContainer.scrollHeight; + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('scrolled down to bottom'); + }); + }); + + story('MobileExampleWithHorizontalPadding', ({ setStoryParameters }) => { + setStoryParameters({ captureElement: null }); + + test('opened', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-comp-name~="DropdownMenu"]' })) + .perform(); + await delay(200); + await this.browser + .actions({ bridge: true }) + .move({ origin: this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' }) }) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); + }); + story('MenuOutOfViewPortRight', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { flacky: { in: ['firefox2022', 'firefox2022Dark'] } }, + }); + outOfViewTests('right'); + }); + story('MenuOutOfViewPortLeft', () => { + outOfViewTests('left'); + }); + + story('WithItemsAndIcons', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }); + + textAlignmentTests(); + }); + + story('WithItemsAndIconsWithoutTextAlignment', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }); + + textAlignmentTests(); + }); + + story('WithNestedMenuItems', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }); + + navigateInNestedMenuItems(); + }); +}); diff --git a/packages/react-ui/components/DropdownMenu/__stories__/DropdownMenu.stories.tsx b/packages/react-ui/components/DropdownMenu/__stories__/DropdownMenu.stories.tsx new file mode 100644 index 00000000000..88dc5f2748e --- /dev/null +++ b/packages/react-ui/components/DropdownMenu/__stories__/DropdownMenu.stories.tsx @@ -0,0 +1,344 @@ +import React, { useState } from 'react'; +import MenuIcon from '@skbkontur/react-icons/Menu'; +import ArrowSize2Icon from '@skbkontur/react-icons/ArrowSize2'; +import SearchIcon from '@skbkontur/react-icons/Search'; +import AddIcon from '@skbkontur/react-icons/Add'; +import DeleteIcon from '@skbkontur/react-icons/Delete'; + +import { Meta, Story } from '../../../typings/stories'; +import { MenuItem } from '../../MenuItem'; +import { MenuHeader } from '../../MenuHeader'; +import { MenuSeparator } from '../../MenuSeparator'; +import { DropdownMenu, DropdownMenuProps } from '../DropdownMenu'; +import { Button } from '../../Button'; +import { Toast } from '../../Toast'; +import { Input } from '../../Input'; +import { Gapped } from '../../Gapped'; +import { OkIcon } from '../../../internal/icons/16px'; +import { ReactUIFeatureFlagsContext } from '../../../lib/featureFlagsContext'; + +export default { + title: 'DropdownMenu', + decorators: [ + (Story: () => JSX.Element) => ( +
+ +
+ ), + ], +} as Meta; + +export const SimpleExample: Story = () => ( + Открыть меню}> + Заголовок меню + + Toast.push('Раз')}>Раз + Toast.push('Два')}>Два + Toast.push('Три')}>Три + +); +SimpleExample.storyName = 'Simple example'; + +const MenuOutOfViewPortSample = ({ side }: { side: 'left' | 'right' }) => { + return ( +
+
+ + Открыть меню}> + Заголовок меню + + Раз два три раз два три + Раз два три раз два три + Раз два три раз два три + + Открыть меню}> + Заголовок меню + + Раз два три раз два три + Раз два три раз два три + Раз два три раз два три + + +
+
+ ); +}; + +export const MenuOutOfViewPortRight: Story = () => { + return ; +}; +MenuOutOfViewPortRight.storyName = 'Menu out of viewport right'; + +export const MenuOutOfViewPortLeft: Story = () => { + return ; +}; +MenuOutOfViewPortLeft.storyName = 'Menu out of viewport left'; + +export const CaptionWidth: Story = () => ( +
+ + Открыть меню + + } + width={'100%'} + > + Заголовок меню + + Toast.push('Раз')}>Раз + Toast.push('Два')}>Два + Toast.push('Три')}>Три + +
+); +CaptionWidth.storyName = 'Caption width 100%'; + +export const ExampleWithWidthOfMenu = () => ( + Открыть меню} menuWidth={350}> + Заголовок меню + + Раз + Два + Три + +); +ExampleWithWidthOfMenu.storyName = 'Example with width of menu'; +ExampleWithWidthOfMenu.parameters = { creevey: { skip: true } }; + +export const ExampleWithMaximumHeightOfMenu = () => ( + Открыть меню} menuMaxHeight={150}> + Заголовок меню + + Раз + Два + Три + +); +ExampleWithMaximumHeightOfMenu.storyName = 'Example with maximum height of menu'; +ExampleWithMaximumHeightOfMenu.parameters = { creevey: { skip: true } }; + +export const CaptionAcceptsAnArbitraryElement = () => ( + + + + } + > + Раз + Два + Три + +); +CaptionAcceptsAnArbitraryElement.storyName = 'Caption accepts an arbitrary element'; +CaptionAcceptsAnArbitraryElement.parameters = { creevey: { skip: true } }; + +export const OnlyStaticElements = () => ( + + + + } + > + Заголовок меню + + Недоступен + +); +OnlyStaticElements.storyName = 'Only static elements'; +OnlyStaticElements.parameters = { creevey: { skip: true } }; + +export const CaptionAcceptsAFunction = () => ( + ( + + + + )} + > + Раз + Два + Три + +); +CaptionAcceptsAFunction.storyName = 'Caption accepts a function'; +CaptionAcceptsAFunction.parameters = { creevey: { skip: true } }; + +export const WithoutAnimations = () => ( + Открыть меню}> + Заголовок меню + + Toast.push('Раз')}>Раз + Toast.push('Два')}>Два + Toast.push('Три')}>Три + +); +WithoutAnimations.storyName = 'Without animations'; +WithoutAnimations.parameters = { creevey: { skip: true } }; + +export const WithHeaderAndFooter: Story = () => ( + Открыть меню} + menuWidth={250} + /> +); +WithHeaderAndFooter.storyName = 'With header and footer'; + +interface DropdownWithScrollStateChangeState { + hasHeader: boolean; + value: string; +} +class DropdownWithScrollStateChange extends React.Component { + public state: DropdownWithScrollStateChangeState = { + value: '', + hasHeader: true, + }; + + public render() { + return ( + + {new Array(50).fill('').map((i, index) => ( + {`Item ${index}`} + ))} + + ); + } + + private header = () => { + return ( +
+ } value={this.state.value} onValueChange={this.handleInputChange} width={220} /> +
+ ); + }; + + private footer = () => { + const { hasHeader } = this.state; + const icon = hasHeader ? : ; + return ( +
+ +
+ ); + }; + + private switchHeaderState = () => { + this.setState((state: DropdownWithScrollStateChangeState) => ({ + hasHeader: !state.hasHeader, + })); + }; + + private handleInputChange = (value: string) => { + this.setState({ value }); + }; + + private resetStateToDefault = () => { + this.setState({ value: '' }); + }; +} + +export const MobileExampleWithHorizontalPadding: Story = () => ( + Открыть меню}> + Заголовок меню + + Toast.push('Раз')}>Раз + Toast.push('Два')}>Два + Toast.push('Три')}>Три + +); + +MobileExampleWithHorizontalPadding.parameters = { + viewport: { + defaultViewport: 'iphone', + }, +}; + +export const WithItemsAndIcons = () => ( + Click me}> + MenuHeader + }>MenuItem1 + }>MenuItem2 + MenuItem3 + +); + +export const WithItemsAndIconsWithoutTextAlignment = () => ( + Click me}> + MenuHeader + }>MenuItem1 + }>MenuItem2 + MenuItem3 + +); + +export const WithNestedMenuItems = () => { + const [caption, setCaption] = useState('not selected'); + const onClick = () => { + setCaption('selected'); + }; + return ( + + {caption}}> + <> +
+ Раз + Два +
+ Три + +
+
+ ); +}; +WithNestedMenuItems.storyName = 'With nested menu items'; From cccff29767272a42ba5150e677874f5cd689a519 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Mon, 13 May 2024 16:23:41 +0500 Subject: [PATCH 030/197] chore: fix FileUploader test --- .../__stories__/FileUploader.stories.tsx | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 packages/react-ui/components/FileUploader/__stories__/FileUploader.stories.tsx diff --git a/packages/react-ui/components/FileUploader/__stories__/FileUploader.stories.tsx b/packages/react-ui/components/FileUploader/__stories__/FileUploader.stories.tsx new file mode 100644 index 00000000000..5f94bce2cd8 --- /dev/null +++ b/packages/react-ui/components/FileUploader/__stories__/FileUploader.stories.tsx @@ -0,0 +1,131 @@ +import React, { useRef } from 'react'; + +import { Button } from '../../Button'; +import { Gapped } from '../../Gapped'; +import { FileUploader, FileUploaderRef } from '../FileUploader'; + +export default { + title: 'FileUploader', + decorators: [(storyFn: () => JSX.Element) =>
{storyFn()}
], +}; + +// eslint-disable-next-line @typescript-eslint/no-empty-function +const loadingRequest = () => new Promise(() => {}); + +const successRequest = () => + new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, 2000); + }); + +const errorRequest = () => + new Promise((resolve, reject) => { + setTimeout(() => { + reject(); + }, 2000); + }); + +/** async control stories **/ +export const SingleAsyncFileUploader = () => ; +export const MultipleAsyncFileUploader = () => ; +MultipleAsyncFileUploader.parameters = { creevey: { skip: true } }; + +export const MultipleAsyncFileUploaderWithLoading = () => ; +MultipleAsyncFileUploaderWithLoading.parameters = { creevey: { skip: true } }; + +export const MultipleAsyncFileUploaderWithErrorRequest = () => ; +MultipleAsyncFileUploaderWithErrorRequest.parameters = { creevey: { skip: true } }; + +/** sync control stories **/ +export const SingleSyncFileUploader = () => ; +SingleSyncFileUploader.parameters = { creevey: { skip: true } }; + +export const MultipleSyncFileUploader = () => ; +MultipleSyncFileUploader.parameters = { creevey: { skip: true } }; + +/** common stories **/ +export const SingleFileUploaderWithFileError = () => ( + Promise.resolve('Формат файла неверный')} /> +); +SingleFileUploaderWithFileError.parameters = { creevey: { skip: true } }; + +export const MultipleFileUploaderWithFileError = () => ( + Promise.resolve('Формат файла неверный')} + /> +); +MultipleFileUploaderWithFileError.parameters = { creevey: { skip: true } }; + +export const DifferentStates = () => ( + + + Error + + + Warning + + + Disabled + + + Error, Warning, Disabled + + +); + +export const CustomWidth = () => ( + + 100% + 550px + +); + +export const FileUploaderRefFocusAndBlur = () => { + const ref = useRef(null); + return ( + + + + + + + ); +}; +FileUploaderRefFocusAndBlur.parameters = { creevey: { skip: true } }; + +export const DifferentSizes = () => ( + + Single + + default + + + small + + + medium + + + large + + Multiple + + default + + + small + + + medium + + + large + + +); + +export const MultipleFileUploaderWithHideFiles = () => ; +MultipleFileUploaderWithHideFiles.parameters = { creevey: { skip: true } }; From ef3399f7c622528bedd1282a6e4094bdbf43320e Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Mon, 13 May 2024 16:26:14 +0500 Subject: [PATCH 031/197] chore: fix FxInput test --- .../FxInput/__creevey__/FxInput.creevey.ts | 21 +++ .../FxInput/__stories__/FxInput.stories.tsx | 173 ++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 packages/react-ui/components/FxInput/__creevey__/FxInput.creevey.ts create mode 100644 packages/react-ui/components/FxInput/__stories__/FxInput.stories.tsx diff --git a/packages/react-ui/components/FxInput/__creevey__/FxInput.creevey.ts b/packages/react-ui/components/FxInput/__creevey__/FxInput.creevey.ts new file mode 100644 index 00000000000..904233fb9c6 --- /dev/null +++ b/packages/react-ui/components/FxInput/__creevey__/FxInput.creevey.ts @@ -0,0 +1,21 @@ +import { story, kind, test } from 'creevey'; + +kind('FxInput', () => { + story('WithWidthStory', () => { + test('inside auto container', async function () { + const element = await this.browser.findElement({ css: '[data-tid="container"]' }); + await this.expect(await element.takeScreenshot()).to.matchImage('inside auto container'); + }); + + test('inside fixed container', async function () { + const element = await this.browser.findElement({ css: '[data-tid="container"]' }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#toggle-width' })) + .perform(); + await this.expect(await element.takeScreenshot()).to.matchImage('inside fixed container'); + }); + }); +}); diff --git a/packages/react-ui/components/FxInput/__stories__/FxInput.stories.tsx b/packages/react-ui/components/FxInput/__stories__/FxInput.stories.tsx new file mode 100644 index 00000000000..0a69695306e --- /dev/null +++ b/packages/react-ui/components/FxInput/__stories__/FxInput.stories.tsx @@ -0,0 +1,173 @@ +import React from 'react'; + +import { Meta, Story } from '../../../typings/stories'; +import { BGRuler } from '../../../internal/BGRuler'; +import { FxInput } from '../FxInput'; +import { Gapped } from '../../Gapped'; +import { createPropsGetter } from '../../../lib/createPropsGetter'; +import { ThemeContext } from '../../../lib/theming/ThemeContext'; +import { FxInputProps } from '..'; +import { SizeProp } from '../../../lib/types/props'; + +export default { title: 'FxInput' } as Meta; + +export const TypeText = () => ; +TypeText.storyName = 'type text'; + +export const DifferentSizesFxInput = () => ( + + + + + +); +DifferentSizesFxInput.storyName = 'different sizes'; + +export const TypeCurrency = () => ; +TypeCurrency.storyName = 'type currency'; + +export const WithDisabled = () => ; +WithDisabled.storyName = 'with disabled'; + +export const Borderless = () => ( + + + +); +Borderless.storyName = 'borderless'; + +export const WithWidthStory: Story = () => ; +WithWidthStory.storyName = 'with width'; + +interface TestFxInputProps { + type: FxInputProps['type']; + borderless?: boolean; + size?: SizeProp; + fractionDigits?: number; +} +interface TestFxInputState { + auto: boolean; + value: React.ReactText; +} +class TestFxInput extends React.Component { + public static defaultProps: { type: TestFxInputProps['type'] } = { + type: 'text', + }; + + private getProps = createPropsGetter(TestFxInput.defaultProps); + + constructor(props: TestFxInputProps) { + super(props); + + this.state = { + auto: false, + value: this.props.type === 'currency' ? 0 : '', + }; + } + + public render(): JSX.Element { + return ( + + ); + } + + private handleChange = (value: React.ReactText) => { + this.setState({ value, auto: false }); + }; + + private handleRestore = () => { + this.setState({ + value: this.props.type === 'currency' ? 111 : 'auto', + auto: true, + }); + }; +} + +interface TestWrapperProps { + width?: number | string; + ruler?: boolean; +} +class TestWrapper extends React.Component> { + public render() { + const { width, ruler, children } = this.props; + const style: React.CSSProperties = { + position: 'relative', + width, + padding: 10, + paddingTop: (ruler && 30) || 10, + marginBottom: 15, + background: '#eee', + }; + const darkStyle: React.CSSProperties = { + ...style, + background: '1f1f1f', + }; + return ( + + {(theme) => { + return ( +
+ {ruler && } + {children} +
+ ); + }} +
+ ); + } +} + +class WithWidth extends React.Component { + public state = { + isFixedWidth: false, + }; + + public render() { + const { isFixedWidth } = this.state; + const FIXED = '200px'; + const AUTO = 'auto'; + const wrapperWidth = isFixedWidth ? FIXED : AUTO; + return ( +
+ +
+
+
+ + + + + + + + + + + + + + + +
+
+ ); + } + + private toggleWidth = () => { + this.setState({ + isFixedWidth: !this.state.isFixedWidth, + }); + }; + + private onChange = () => null; +} From 0af3607f910b7f0c5bd8148fcad8339669e48a9e Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Mon, 13 May 2024 16:27:56 +0500 Subject: [PATCH 032/197] chore: fix Gapped test --- .../Gapped/__stories__/Gapped.stories.tsx | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 packages/react-ui/components/Gapped/__stories__/Gapped.stories.tsx diff --git a/packages/react-ui/components/Gapped/__stories__/Gapped.stories.tsx b/packages/react-ui/components/Gapped/__stories__/Gapped.stories.tsx new file mode 100644 index 00000000000..deb92c0886f --- /dev/null +++ b/packages/react-ui/components/Gapped/__stories__/Gapped.stories.tsx @@ -0,0 +1,91 @@ +import React from 'react'; + +import { Meta } from '../../../typings/stories'; +import { Gapped, GappedProps } from '../Gapped'; +import { Button } from '../../Button'; + +export default { + title: 'Gapped', + decorators: [ + (Story: () => JSX.Element) => ( +
+ +
+ ), + ], +} as Meta; + +export const Horizontal = () => ( + + + + +); + +export const Vertical = () => ( + + + + +); + +export const HorizontalWrap = () => ( + + + + + + +); + +export const HorizontalNoWrap = () => ( + + + + + + +); + +interface WithFalsyChildsProps extends Partial> { + falsyChild?: React.ReactNode; +} +export const WithFalsyChilds = () => { + const GappedWithFalsyChilds = ({ falsyChild = null, ...props }: WithFalsyChildsProps) => ( + + {falsyChild} + + {falsyChild} + + {falsyChild} + + ); + const falsyValues = [false, '', 0, null, undefined]; + return falsyValues.map((value, index) => ( + <> + + + + + + + + + + + + + + + + +
+ with "{String(value)}"
horizontal + +
vertical + +
+ {index + 1 < falsyValues.length &&
} + + )); +}; From 00be7d613371912ba92c7dc43c0a8b2386069de4 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Mon, 13 May 2024 16:28:41 +0500 Subject: [PATCH 033/197] chore: fix GlobalLoader test --- .../__stories__/GlobalLoader.stories.tsx | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 packages/react-ui/components/GlobalLoader/__stories__/GlobalLoader.stories.tsx diff --git a/packages/react-ui/components/GlobalLoader/__stories__/GlobalLoader.stories.tsx b/packages/react-ui/components/GlobalLoader/__stories__/GlobalLoader.stories.tsx new file mode 100644 index 00000000000..dd13f9adcea --- /dev/null +++ b/packages/react-ui/components/GlobalLoader/__stories__/GlobalLoader.stories.tsx @@ -0,0 +1,140 @@ +import React from 'react'; +import { Select, Toast, GlobalLoader, Button } from '@skbkontur/react-ui'; + +import { Story } from '../../../typings/stories'; + +function GlobalLoaderWithProps() { + const [error, setError] = React.useState(false); + const [active, setActive] = React.useState(false); + + return ( +
+ + +
+ ); + + function showGlobalLoaderWithProps() { + setTimeout(() => { + setActive(true); + }, 1000); + + setTimeout(() => { + setError(true); + }, 10000); + + setTimeout(() => { + setActive(false); + }, 30000); + } +} + +function GlobalLoaderWithStaticMethods() { + return ( +
+ + + + + +
+ ); + + function showGlobalLoader() { + GlobalLoader.start(); + } + + function sendSuccess() { + GlobalLoader.done(); + } + + function sendReject() { + GlobalLoader.reject(); + } + + function sendAccept() { + GlobalLoader.accept(); + } +} + +function GlobalLoaderWithTimer() { + const [active, setActive] = React.useState(false); + const [time, setTime] = React.useState(1); + const [timerTime, setTimerTime] = React.useState(0); + const [expectedResponseTime, setExpectedResponseTime] = React.useState(2); + const [done, setDone] = React.useState(true); + const times = [0.5, 1, 2, 4, 8, 16]; + let timer: ReturnType | null = null; + return ( +
+
+ Выберите ожидаемое время ответа от сервера (expectedResponseTime): + items={times} value={expectedResponseTime} onValueChange={setExpectedResponseTime} /> + секунд +
+
+ Выберите реальное время ответа от сервера: + items={times} value={time} onValueChange={setTime} /> + Прошло: {timerTime / 1000} секунд +
+ + { + setDone(true); + }} + /> + +
+ ); + function startGlobalLoader() { + setActive(true); + setDone(false); + setTimerTime(0); + startTimer(); + setTimeout(() => { + setActive(false); + Toast.push('Загрузка завершена'); + }, time * 1000); + } + function startTimer() { + if (!timer) { + let currentTime = 0; + timer = setInterval(() => { + setTimerTime(currentTime); + currentTime += 100; + if (currentTime > time * 1000) { + if (timer) { + clearInterval(timer); + timer = null; + } + } + }, 100); + } + } +} + +export default { title: 'GlobalLoader' }; + +export const GlobalLoaderWithPropsContent: Story = () => ; +GlobalLoaderWithPropsContent.storyName = 'with props'; +GlobalLoaderWithPropsContent.parameters = { creevey: { skip: true } }; + +export const GlobalLoaderWithStaticMethodsContent: Story = () => ; +GlobalLoaderWithStaticMethodsContent.storyName = 'with static methods'; +GlobalLoaderWithStaticMethodsContent.parameters = { creevey: { skip: true } }; + +export const GlobalLoaderWithTimerContent: Story = () => ; +GlobalLoaderWithTimerContent.storyName = 'with timer'; +GlobalLoaderWithTimerContent.parameters = { creevey: { skip: true } }; From 0bc33ad160b93435e1f8bc995984fe45eba3c733 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Mon, 13 May 2024 16:30:41 +0500 Subject: [PATCH 034/197] chore: fix Group test --- .../Group/__creevey__/Group.creevey.ts | 19 ++++ .../Group/__stories__/Group.stories.tsx | 96 +++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 packages/react-ui/components/Group/__creevey__/Group.creevey.ts create mode 100644 packages/react-ui/components/Group/__stories__/Group.stories.tsx diff --git a/packages/react-ui/components/Group/__creevey__/Group.creevey.ts b/packages/react-ui/components/Group/__creevey__/Group.creevey.ts new file mode 100644 index 00000000000..00f882d716b --- /dev/null +++ b/packages/react-ui/components/Group/__creevey__/Group.creevey.ts @@ -0,0 +1,19 @@ +import { story, kind, test } from 'creevey'; + +kind('Group', () => { + story('SimpleGroupWithInputAndButton', () => { + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('focused input', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'input' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('focused input'); + }); + }); +}); diff --git a/packages/react-ui/components/Group/__stories__/Group.stories.tsx b/packages/react-ui/components/Group/__stories__/Group.stories.tsx new file mode 100644 index 00000000000..e46b3d2b964 --- /dev/null +++ b/packages/react-ui/components/Group/__stories__/Group.stories.tsx @@ -0,0 +1,96 @@ +import React from 'react'; +import UserIcon from '@skbkontur/react-icons/User'; +import SearchIcon from '@skbkontur/react-icons/Search'; +import DeleteIcon from '@skbkontur/react-icons/Delete'; + +import { Story } from '../../../typings/stories'; +import { BGRuler } from '../../../internal/BGRuler'; +import { Group } from '../Group'; +import { Input } from '../../Input'; +import { Button } from '../../Button'; +import { Toast } from '../../Toast'; +import { ThemeContext } from '../../../lib/theming/ThemeContext'; + +export default { title: 'Group' }; + +export const SimpleGroupWithInputAndButton: Story = () => ( + + + + + + +); +GroupWithInputAndMultipleButtons.storyName = 'Group with Input and multiple Buttons'; +GroupWithInputAndMultipleButtons.parameters = { creevey: { skip: true } }; + +export const ButtonGroup = () => ( + + + + + +); +ButtonGroup.storyName = 'Button group'; + +export const ComplexElements = () => ( + + + +); +ComplexElements.storyName = 'Complex elements'; +ComplexElements.parameters = { creevey: { skip: true } }; + +export const WithWidth = () => ( + + {(theme) => { + return ( +
+ + + + + +
+
+ + + + +
+ ); + }} +
+); +WithWidth.storyName = 'With width'; From c56fbe59e7a6be52a232097de1e6fc6eebc65431 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Mon, 13 May 2024 16:31:39 +0500 Subject: [PATCH 035/197] chore: fix Hint test --- .../Hint/__creevey__/Hint.creevey.ts | 67 ++++ .../Hint/__stories__/Hint.stories.tsx | 360 ++++++++++++++++++ 2 files changed, 427 insertions(+) create mode 100644 packages/react-ui/components/Hint/__creevey__/Hint.creevey.ts create mode 100644 packages/react-ui/components/Hint/__stories__/Hint.stories.tsx diff --git a/packages/react-ui/components/Hint/__creevey__/Hint.creevey.ts b/packages/react-ui/components/Hint/__creevey__/Hint.creevey.ts new file mode 100644 index 00000000000..b3edf5356e8 --- /dev/null +++ b/packages/react-ui/components/Hint/__creevey__/Hint.creevey.ts @@ -0,0 +1,67 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('Hint', () => { + story('SetManualAndOpenedPropOnClick', () => { + test('click on hint', async function () { + await this.browser + .actions() + .click(this.browser.findElement({ css: '#main' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('click on hint'); + }); + }); + + story('WithSVGIcon', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'internal logic being tested and not something UI related': { + in: [ + 'chromeDark', + 'chrome8px', + 'firefox8px', + 'firefox', + 'firefoxFlat8px', + 'firefoxDark', + 'ie118px', + 'ie11', + 'ie11Dark', + ], + }, + }, + }); + + test('idle', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('idle'); + }); + + test('hover', async function () { + await this.browser + .actions() + .move({ + origin: this.browser.findElement({ css: '[data-tid="icon"]' }), + }) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open'); + }); + }); + story('top bottom center', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b)/ } }, + }); + }); + story('KebabHintRemovePinFeatureFlag', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'only for 22 theme': { in: /^(?!\b.*2022.*\b)/ } }, + }); + }); + story('HintNearScreenEdge', ({ setStoryParameters }) => { + setStoryParameters({ + captureElement: 'body', + skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } }, + }); + }); +}); diff --git a/packages/react-ui/components/Hint/__stories__/Hint.stories.tsx b/packages/react-ui/components/Hint/__stories__/Hint.stories.tsx new file mode 100644 index 00000000000..cd6d2bc02d4 --- /dev/null +++ b/packages/react-ui/components/Hint/__stories__/Hint.stories.tsx @@ -0,0 +1,360 @@ +import React from 'react'; + +import { Meta, Story } from '../../../typings/stories'; +import { Hint } from '../Hint'; +import { Gapped } from '../../Gapped'; +import { Input } from '../../Input'; +import { PopupPositions } from '../../../internal/Popup'; +import { Textarea } from '../../Textarea'; +import { rootNode, TSetRootNode } from '../../../lib/rootNode'; +import { Button } from '../../Button'; +import { Tooltip } from '../../Tooltip'; +import { ReactUIFeatureFlagsContext } from '../../../lib/featureFlagsContext'; + +export default { + title: 'Hint', + decorators: [ + (Story: () => JSX.Element) => ( +
+ +
+ ), + ], +} as Meta; + +export const Playground = () => Plain hint with knobs; +Playground.storyName = 'playground'; +Playground.parameters = { creevey: { skip: true } }; + +export const TooMuchHints = () => ( + + {new Array(252).fill(null).map((_el, i) => ( + + Hover me! + + ))} + +); +TooMuchHints.storyName = 'too much hints'; +TooMuchHints.parameters = { creevey: { skip: true } }; + +export const Default = () => ( + + Ich Liebe dich + +); +Default.storyName = 'default'; + +export const Left = () => ( + + Je t'aime + +); +Left.storyName = 'left'; + +export const Right = () => ( + + Ti voglio bene + +); +Right.storyName = 'right'; + +export const Bottom = () => ( + + Te amo + +); +Bottom.storyName = 'bottom'; + +export const TopBottomCenter = () => ( +
+ + Top + + + + Bottom + +
+); +TopBottomCenter.storyName = 'top bottom center'; + +export const WithLargeWord = () => ( +
+ + Там длинное слово + +
+); +WithLargeWord.storyName = 'with large word'; + +export const WithBlockElement = () => ( + +
+ Ti voglio bene +
+
+); +WithBlockElement.storyName = 'with block-element'; + +export const With100WidthInput = () => ( + + + + + +); +With100WidthInput.storyName = 'with 100%-width input'; + +export const HintWithoutAnimations = () => ( +
+ + + + + + + + + +
+); +HintWithoutAnimations.storyName = 'hint without animations'; +HintWithoutAnimations.parameters = { creevey: { skip: true } }; + +export const HintsWithoutWrapperAroundInlineBlockWith50Width: Story = () => ( +
+ {PopupPositions.reduce( + (child, position) => ( + + {child} + + ), + , + )} +
+); +HintsWithoutWrapperAroundInlineBlockWith50Width.storyName = 'Hints without wrapper around inline-block with 50% width'; +HintsWithoutWrapperAroundInlineBlockWith50Width.parameters = { creevey: { delay: 500 } }; + +const HandleClickHint = () => { + const [manual, setManual] = React.useState(false); + + const onClick = () => setManual(true); + + return ( +
+ +
+ Hover me and click +
+
+
+ ); +}; + +export const SetManualAndOpenedPropOnClick: Story = () => ; + +export const WithSVGIcon: Story = () => { + return ( + + + + + + ); +}; + +@rootNode +class CustomClassComponent extends React.Component { + private setRootNode!: TSetRootNode; + + render() { + return
Ich Liebe dich
; + } +} +export const WithClassChildren = () => ( + + + + + +); +WithClassChildren.storyName = 'with class children'; + +export const KebabHintRemovePinFeatureFlag = () => ( + + + Ich Liebe dich + + +); +KebabHintRemovePinFeatureFlag.storyName = 'with kebabHintRemovePin feature flag'; + +export const HintNearScreenEdge = () => ( + <> +
+
+ + + +
Hey there!
} pos="bottom center" trigger="opened"> + +
+
+ +
+ + + +
Hey there!
} pos="bottom center" trigger="opened"> + +
+
+ +
+ + + +
Hey there!
} pos="bottom center" trigger="opened"> + +
+
+ +
+ + + +
Hey there!
} pos="bottom center" trigger="opened"> + +
+
+ +
+ + + +
Hey there!
} pos="bottom center" trigger="opened"> + +
+
+ +
+ + + +
+
+ + +
+ + + +
Hey there!
} pos="bottom center" trigger="opened"> + +
+
+ +
+ + + +
Hey there!
} pos="bottom center" trigger="opened"> + +
+
+ +
+ + + +
Hey there!
} pos="bottom center" trigger="opened"> + +
+
+ +
+ + + +
Hey there!
} pos="bottom center" trigger="opened"> + +
+
+ +
+ + + +
Hey there!
} pos="bottom center" trigger="opened"> + +
+
+ +
+ + + +
+
+ +); +HintNearScreenEdge.storyName = 'hint near screen edge'; From c1a5efbbdbdf87339d26e051b9f4b9e798d2da74 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Tue, 14 May 2024 10:39:14 +0500 Subject: [PATCH 036/197] chore: fix Input test --- .../Default/Focused/chrome/Focused.png | 0 .../Default/Focused/firefox/Focused.png | 0 .../Default/Focused/ie11/Focused.png | 0 .../Default/Plain/chrome/Plain.png | 0 .../Default/Plain/firefox/Plain.png | 0 .../Default/Plain/ie11/Plain.png | 0 .../chrome/With long typed text.png | 0 .../firefox/With long typed text.png | 0 .../ie11/With long typed text.png | 0 .../chrome/With typed text.png | 0 .../firefox/With typed text.png | 0 .../With typed text/ie11/With typed text.png | 0 .../Focused/chromeDark/Focused.png | 3 - .../Input Type Api/Focused/chrome/Focused.png | 0 .../Focused/chromeDark/Focused.png | 0 .../Focused/firefox/Focused.png | 0 .../Focused/firefoxDark/Focused.png | 0 .../Input Type Api/Focused/ie11/Focused.png | 0 .../Max Length/Focused/chrome/Focused.png | 0 .../Max Length/Focused/firefox/Focused.png | 0 .../Max Length/Focused/ie11/Focused.png | 0 .../Max Length/Plain/chrome/Plain.png | 0 .../Max Length/Plain/firefox/Plain.png | 0 .../Max Length/Plain/ie11/Plain.png | 0 .../chrome/With long typed text.png | 0 .../firefox/With long typed text.png | 0 .../ie11/With long typed text.png | 0 .../chrome/With typed text.png | 0 .../firefox/With typed text.png | 0 .../With typed text/ie11/With typed text.png | 0 .../Focused/chrome/Focused.png | 0 .../Focused/chromeDark/Focused.png | 3 + .../Focused/chrome/Focused.png | 0 .../Focused/firefox/Focused.png | 0 .../Focused/ie11/Focused.png | 0 .../Select All By Prop/Plain/chrome/Plain.png | 0 .../Plain/firefox/Plain.png | 0 .../Select All By Prop/Plain/ie11/Plain.png | 0 .../Plain/chrome/Plain.png | 0 .../Plain/firefox/Plain.png | 0 .../Select all by button/Plain/ie11/Plain.png | 0 .../Selected/chrome/Selected.png | 0 .../Selected/firefox/Selected.png | 0 .../Selected/ie11/Selected.png | 0 .../images/Input/Type Api/firefox.png | 4 +- .../.creevey/images/Input/Type/firefox.png | 4 +- .../PlainAndTyped/chrome/plain.png | 0 .../PlainAndTyped/chrome/typed.png | 0 .../PlainAndTyped/firefox/plain.png | 0 .../PlainAndTyped/firefox/typed.png | 0 .../PlainAndTyped/ie11/plain.png | 0 .../PlainAndTyped/ie11/typed.png | 0 .../idle, focus, edit, blur/chrome/blured.png | 0 .../idle, focus, edit, blur/chrome/edited.png | 0 .../chrome/focused.png | 0 .../idle, focus, edit, blur/chrome/idle.png | 0 .../firefox/blured.png | 0 .../firefox/edited.png | 0 .../firefox/focused.png | 0 .../idle, focus, edit, blur/firefox/idle.png | 0 .../idle, focus, edit, blur/ie11/blured.png | 0 .../idle, focus, edit, blur/ie11/edited.png | 0 .../idle, focus, edit, blur/ie11/focused.png | 0 .../idle, focus, edit, blur/ie11/idle.png | 0 .../PlainAndSelected/chrome/plain.png | 0 .../chrome/selectAllFilledInput.png | 0 .../chrome/selectAllHalfFilledInput.png | 0 .../idle, focus, edit, blur/chrome/blured.png | 0 .../idle, focus, edit, blur/chrome/edited.png | 0 .../chrome/focused.png | 0 .../idle, focus, edit, blur/chrome/idle.png | 0 .../firefox/blured.png | 0 .../firefox/edited.png | 0 .../firefox/focused.png | 0 .../idle, focus, edit, blur/firefox/idle.png | 0 .../idle, focus, edit, blur/ie11/blured.png | 0 .../idle, focus, edit, blur/ie11/edited.png | 0 .../idle, focus, edit, blur/ie11/focused.png | 0 .../idle, focus, edit, blur/ie11/idle.png | 0 .../Input/__creevey__/Input.creevey.ts | 233 +++++++++ .../Input/__stories__/Input.stories.tsx | 459 ++++++++++++++++++ 81 files changed, 699 insertions(+), 7 deletions(-) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Default/Focused/chrome/Focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Default/Focused/firefox/Focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Default/Focused/ie11/Focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Default/Plain/chrome/Plain.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Default/Plain/firefox/Plain.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Default/Plain/ie11/Plain.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Default/With long typed text/chrome/With long typed text.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Default/With long typed text/firefox/With long typed text.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Default/With long typed text/ie11/With long typed text.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Default/With typed text/chrome/With typed text.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Default/With typed text/firefox/With typed text.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Default/With typed text/ie11/With typed text.png (100%) delete mode 100644 packages/react-ui/.creevey/images/Input/Functional tests/Search Type Api/Focused/chromeDark/Focused.png rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Input Type Api/Focused/chrome/Focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Input Type Api/Focused/chromeDark/Focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Input Type Api/Focused/firefox/Focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Input Type Api/Focused/firefoxDark/Focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Input Type Api/Focused/ie11/Focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Max Length/Focused/chrome/Focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Max Length/Focused/firefox/Focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Max Length/Focused/ie11/Focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Max Length/Plain/chrome/Plain.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Max Length/Plain/firefox/Plain.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Max Length/Plain/ie11/Plain.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Max Length/With long typed text/chrome/With long typed text.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Max Length/With long typed text/firefox/With long typed text.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Max Length/With long typed text/ie11/With long typed text.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Max Length/With typed text/chrome/With typed text.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Max Length/With typed text/firefox/With typed text.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Max Length/With typed text/ie11/With typed text.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Search Type Api/Focused/chrome/Focused.png (100%) create mode 100644 packages/react-ui/.creevey/images/Input/Search Type Api/Focused/chromeDark/Focused.png rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Select All By Prop/Focused/chrome/Focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Select All By Prop/Focused/firefox/Focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Select All By Prop/Focused/ie11/Focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Select All By Prop/Plain/chrome/Plain.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Select All By Prop/Plain/firefox/Plain.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Select All By Prop/Plain/ie11/Plain.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Select all by button/Plain/chrome/Plain.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Select all by button/Plain/firefox/Plain.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Select all by button/Plain/ie11/Plain.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Select all by button/Selected/chrome/Selected.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Select all by button/Selected/firefox/Selected.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Select all by button/Selected/ie11/Selected.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/plain.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/typed.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/plain.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/typed.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Uncontrolled Input with Placeholder/PlainAndTyped/ie11/plain.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/Uncontrolled Input with Placeholder/PlainAndTyped/ie11/typed.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/blured.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/edited.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/idle.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/blured.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/edited.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/idle.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/blured.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/edited.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/idle.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask And Select All Prop/PlainAndSelected/chrome/plain.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask And Select All Prop/PlainAndSelected/chrome/selectAllFilledInput.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask And Select All Prop/PlainAndSelected/chrome/selectAllHalfFilledInput.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask/idle, focus, edit, blur/chrome/blured.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask/idle, focus, edit, blur/chrome/edited.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask/idle, focus, edit, blur/chrome/focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask/idle, focus, edit, blur/chrome/idle.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask/idle, focus, edit, blur/firefox/blured.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask/idle, focus, edit, blur/firefox/edited.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask/idle, focus, edit, blur/firefox/focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask/idle, focus, edit, blur/firefox/idle.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask/idle, focus, edit, blur/ie11/blured.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask/idle, focus, edit, blur/ie11/edited.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask/idle, focus, edit, blur/ie11/focused.png (100%) rename packages/react-ui/.creevey/images/Input/{Functional tests => }/With Mask/idle, focus, edit, blur/ie11/idle.png (100%) create mode 100644 packages/react-ui/components/Input/__creevey__/Input.creevey.ts create mode 100644 packages/react-ui/components/Input/__stories__/Input.stories.tsx diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Default/Focused/chrome/Focused.png b/packages/react-ui/.creevey/images/Input/Default/Focused/chrome/Focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Default/Focused/chrome/Focused.png rename to packages/react-ui/.creevey/images/Input/Default/Focused/chrome/Focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Default/Focused/firefox/Focused.png b/packages/react-ui/.creevey/images/Input/Default/Focused/firefox/Focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Default/Focused/firefox/Focused.png rename to packages/react-ui/.creevey/images/Input/Default/Focused/firefox/Focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Default/Focused/ie11/Focused.png b/packages/react-ui/.creevey/images/Input/Default/Focused/ie11/Focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Default/Focused/ie11/Focused.png rename to packages/react-ui/.creevey/images/Input/Default/Focused/ie11/Focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Default/Plain/chrome/Plain.png b/packages/react-ui/.creevey/images/Input/Default/Plain/chrome/Plain.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Default/Plain/chrome/Plain.png rename to packages/react-ui/.creevey/images/Input/Default/Plain/chrome/Plain.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Default/Plain/firefox/Plain.png b/packages/react-ui/.creevey/images/Input/Default/Plain/firefox/Plain.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Default/Plain/firefox/Plain.png rename to packages/react-ui/.creevey/images/Input/Default/Plain/firefox/Plain.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Default/Plain/ie11/Plain.png b/packages/react-ui/.creevey/images/Input/Default/Plain/ie11/Plain.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Default/Plain/ie11/Plain.png rename to packages/react-ui/.creevey/images/Input/Default/Plain/ie11/Plain.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Default/With long typed text/chrome/With long typed text.png b/packages/react-ui/.creevey/images/Input/Default/With long typed text/chrome/With long typed text.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Default/With long typed text/chrome/With long typed text.png rename to packages/react-ui/.creevey/images/Input/Default/With long typed text/chrome/With long typed text.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Default/With long typed text/firefox/With long typed text.png b/packages/react-ui/.creevey/images/Input/Default/With long typed text/firefox/With long typed text.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Default/With long typed text/firefox/With long typed text.png rename to packages/react-ui/.creevey/images/Input/Default/With long typed text/firefox/With long typed text.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Default/With long typed text/ie11/With long typed text.png b/packages/react-ui/.creevey/images/Input/Default/With long typed text/ie11/With long typed text.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Default/With long typed text/ie11/With long typed text.png rename to packages/react-ui/.creevey/images/Input/Default/With long typed text/ie11/With long typed text.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Default/With typed text/chrome/With typed text.png b/packages/react-ui/.creevey/images/Input/Default/With typed text/chrome/With typed text.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Default/With typed text/chrome/With typed text.png rename to packages/react-ui/.creevey/images/Input/Default/With typed text/chrome/With typed text.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Default/With typed text/firefox/With typed text.png b/packages/react-ui/.creevey/images/Input/Default/With typed text/firefox/With typed text.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Default/With typed text/firefox/With typed text.png rename to packages/react-ui/.creevey/images/Input/Default/With typed text/firefox/With typed text.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Default/With typed text/ie11/With typed text.png b/packages/react-ui/.creevey/images/Input/Default/With typed text/ie11/With typed text.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Default/With typed text/ie11/With typed text.png rename to packages/react-ui/.creevey/images/Input/Default/With typed text/ie11/With typed text.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Search Type Api/Focused/chromeDark/Focused.png b/packages/react-ui/.creevey/images/Input/Functional tests/Search Type Api/Focused/chromeDark/Focused.png deleted file mode 100644 index df43afb080c..00000000000 --- a/packages/react-ui/.creevey/images/Input/Functional tests/Search Type Api/Focused/chromeDark/Focused.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5424fcf9ec75e13707f2a97bfee0302c26ec9f67e16f11097f8ae69334115ac8 -size 2011 diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Input Type Api/Focused/chrome/Focused.png b/packages/react-ui/.creevey/images/Input/Input Type Api/Focused/chrome/Focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Input Type Api/Focused/chrome/Focused.png rename to packages/react-ui/.creevey/images/Input/Input Type Api/Focused/chrome/Focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Input Type Api/Focused/chromeDark/Focused.png b/packages/react-ui/.creevey/images/Input/Input Type Api/Focused/chromeDark/Focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Input Type Api/Focused/chromeDark/Focused.png rename to packages/react-ui/.creevey/images/Input/Input Type Api/Focused/chromeDark/Focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Input Type Api/Focused/firefox/Focused.png b/packages/react-ui/.creevey/images/Input/Input Type Api/Focused/firefox/Focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Input Type Api/Focused/firefox/Focused.png rename to packages/react-ui/.creevey/images/Input/Input Type Api/Focused/firefox/Focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Input Type Api/Focused/firefoxDark/Focused.png b/packages/react-ui/.creevey/images/Input/Input Type Api/Focused/firefoxDark/Focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Input Type Api/Focused/firefoxDark/Focused.png rename to packages/react-ui/.creevey/images/Input/Input Type Api/Focused/firefoxDark/Focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Input Type Api/Focused/ie11/Focused.png b/packages/react-ui/.creevey/images/Input/Input Type Api/Focused/ie11/Focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Input Type Api/Focused/ie11/Focused.png rename to packages/react-ui/.creevey/images/Input/Input Type Api/Focused/ie11/Focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Max Length/Focused/chrome/Focused.png b/packages/react-ui/.creevey/images/Input/Max Length/Focused/chrome/Focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Max Length/Focused/chrome/Focused.png rename to packages/react-ui/.creevey/images/Input/Max Length/Focused/chrome/Focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Max Length/Focused/firefox/Focused.png b/packages/react-ui/.creevey/images/Input/Max Length/Focused/firefox/Focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Max Length/Focused/firefox/Focused.png rename to packages/react-ui/.creevey/images/Input/Max Length/Focused/firefox/Focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Max Length/Focused/ie11/Focused.png b/packages/react-ui/.creevey/images/Input/Max Length/Focused/ie11/Focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Max Length/Focused/ie11/Focused.png rename to packages/react-ui/.creevey/images/Input/Max Length/Focused/ie11/Focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Max Length/Plain/chrome/Plain.png b/packages/react-ui/.creevey/images/Input/Max Length/Plain/chrome/Plain.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Max Length/Plain/chrome/Plain.png rename to packages/react-ui/.creevey/images/Input/Max Length/Plain/chrome/Plain.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Max Length/Plain/firefox/Plain.png b/packages/react-ui/.creevey/images/Input/Max Length/Plain/firefox/Plain.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Max Length/Plain/firefox/Plain.png rename to packages/react-ui/.creevey/images/Input/Max Length/Plain/firefox/Plain.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Max Length/Plain/ie11/Plain.png b/packages/react-ui/.creevey/images/Input/Max Length/Plain/ie11/Plain.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Max Length/Plain/ie11/Plain.png rename to packages/react-ui/.creevey/images/Input/Max Length/Plain/ie11/Plain.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Max Length/With long typed text/chrome/With long typed text.png b/packages/react-ui/.creevey/images/Input/Max Length/With long typed text/chrome/With long typed text.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Max Length/With long typed text/chrome/With long typed text.png rename to packages/react-ui/.creevey/images/Input/Max Length/With long typed text/chrome/With long typed text.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Max Length/With long typed text/firefox/With long typed text.png b/packages/react-ui/.creevey/images/Input/Max Length/With long typed text/firefox/With long typed text.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Max Length/With long typed text/firefox/With long typed text.png rename to packages/react-ui/.creevey/images/Input/Max Length/With long typed text/firefox/With long typed text.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Max Length/With long typed text/ie11/With long typed text.png b/packages/react-ui/.creevey/images/Input/Max Length/With long typed text/ie11/With long typed text.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Max Length/With long typed text/ie11/With long typed text.png rename to packages/react-ui/.creevey/images/Input/Max Length/With long typed text/ie11/With long typed text.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Max Length/With typed text/chrome/With typed text.png b/packages/react-ui/.creevey/images/Input/Max Length/With typed text/chrome/With typed text.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Max Length/With typed text/chrome/With typed text.png rename to packages/react-ui/.creevey/images/Input/Max Length/With typed text/chrome/With typed text.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Max Length/With typed text/firefox/With typed text.png b/packages/react-ui/.creevey/images/Input/Max Length/With typed text/firefox/With typed text.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Max Length/With typed text/firefox/With typed text.png rename to packages/react-ui/.creevey/images/Input/Max Length/With typed text/firefox/With typed text.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Max Length/With typed text/ie11/With typed text.png b/packages/react-ui/.creevey/images/Input/Max Length/With typed text/ie11/With typed text.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Max Length/With typed text/ie11/With typed text.png rename to packages/react-ui/.creevey/images/Input/Max Length/With typed text/ie11/With typed text.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Search Type Api/Focused/chrome/Focused.png b/packages/react-ui/.creevey/images/Input/Search Type Api/Focused/chrome/Focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Search Type Api/Focused/chrome/Focused.png rename to packages/react-ui/.creevey/images/Input/Search Type Api/Focused/chrome/Focused.png diff --git a/packages/react-ui/.creevey/images/Input/Search Type Api/Focused/chromeDark/Focused.png b/packages/react-ui/.creevey/images/Input/Search Type Api/Focused/chromeDark/Focused.png new file mode 100644 index 00000000000..91e7691e2ac --- /dev/null +++ b/packages/react-ui/.creevey/images/Input/Search Type Api/Focused/chromeDark/Focused.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8f5ec5f31fe7055f5658cb3404f5634980616476a97cd5aafc69a0e8ac1433eb +size 1726 diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Select All By Prop/Focused/chrome/Focused.png b/packages/react-ui/.creevey/images/Input/Select All By Prop/Focused/chrome/Focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Select All By Prop/Focused/chrome/Focused.png rename to packages/react-ui/.creevey/images/Input/Select All By Prop/Focused/chrome/Focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Select All By Prop/Focused/firefox/Focused.png b/packages/react-ui/.creevey/images/Input/Select All By Prop/Focused/firefox/Focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Select All By Prop/Focused/firefox/Focused.png rename to packages/react-ui/.creevey/images/Input/Select All By Prop/Focused/firefox/Focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Select All By Prop/Focused/ie11/Focused.png b/packages/react-ui/.creevey/images/Input/Select All By Prop/Focused/ie11/Focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Select All By Prop/Focused/ie11/Focused.png rename to packages/react-ui/.creevey/images/Input/Select All By Prop/Focused/ie11/Focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Select All By Prop/Plain/chrome/Plain.png b/packages/react-ui/.creevey/images/Input/Select All By Prop/Plain/chrome/Plain.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Select All By Prop/Plain/chrome/Plain.png rename to packages/react-ui/.creevey/images/Input/Select All By Prop/Plain/chrome/Plain.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Select All By Prop/Plain/firefox/Plain.png b/packages/react-ui/.creevey/images/Input/Select All By Prop/Plain/firefox/Plain.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Select All By Prop/Plain/firefox/Plain.png rename to packages/react-ui/.creevey/images/Input/Select All By Prop/Plain/firefox/Plain.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Select All By Prop/Plain/ie11/Plain.png b/packages/react-ui/.creevey/images/Input/Select All By Prop/Plain/ie11/Plain.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Select All By Prop/Plain/ie11/Plain.png rename to packages/react-ui/.creevey/images/Input/Select All By Prop/Plain/ie11/Plain.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Select all by button/Plain/chrome/Plain.png b/packages/react-ui/.creevey/images/Input/Select all by button/Plain/chrome/Plain.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Select all by button/Plain/chrome/Plain.png rename to packages/react-ui/.creevey/images/Input/Select all by button/Plain/chrome/Plain.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Select all by button/Plain/firefox/Plain.png b/packages/react-ui/.creevey/images/Input/Select all by button/Plain/firefox/Plain.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Select all by button/Plain/firefox/Plain.png rename to packages/react-ui/.creevey/images/Input/Select all by button/Plain/firefox/Plain.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Select all by button/Plain/ie11/Plain.png b/packages/react-ui/.creevey/images/Input/Select all by button/Plain/ie11/Plain.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Select all by button/Plain/ie11/Plain.png rename to packages/react-ui/.creevey/images/Input/Select all by button/Plain/ie11/Plain.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Select all by button/Selected/chrome/Selected.png b/packages/react-ui/.creevey/images/Input/Select all by button/Selected/chrome/Selected.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Select all by button/Selected/chrome/Selected.png rename to packages/react-ui/.creevey/images/Input/Select all by button/Selected/chrome/Selected.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Select all by button/Selected/firefox/Selected.png b/packages/react-ui/.creevey/images/Input/Select all by button/Selected/firefox/Selected.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Select all by button/Selected/firefox/Selected.png rename to packages/react-ui/.creevey/images/Input/Select all by button/Selected/firefox/Selected.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Select all by button/Selected/ie11/Selected.png b/packages/react-ui/.creevey/images/Input/Select all by button/Selected/ie11/Selected.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Select all by button/Selected/ie11/Selected.png rename to packages/react-ui/.creevey/images/Input/Select all by button/Selected/ie11/Selected.png diff --git a/packages/react-ui/.creevey/images/Input/Type Api/firefox.png b/packages/react-ui/.creevey/images/Input/Type Api/firefox.png index a49df67d8d9..9519b646f72 100644 --- a/packages/react-ui/.creevey/images/Input/Type Api/firefox.png +++ b/packages/react-ui/.creevey/images/Input/Type Api/firefox.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:975b0f7cc14a38e47c2bc2005876eb722074c879600260309437d21193a0d210 -size 87450 +oid sha256:f01277573e019ea2ec76a686804413113bd4480a43486106c414daa1c64b1deb +size 87446 diff --git a/packages/react-ui/.creevey/images/Input/Type/firefox.png b/packages/react-ui/.creevey/images/Input/Type/firefox.png index 12f8ff6c578..782c0230390 100644 --- a/packages/react-ui/.creevey/images/Input/Type/firefox.png +++ b/packages/react-ui/.creevey/images/Input/Type/firefox.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:373f58e6ebe3b064867cf13f22e7a1e2542b03a1fa82795b98ce8b69e8caf7dd -size 92743 +oid sha256:3f9b9b53fe05a2424fad1679f21e5a18c51064cb574abff2dd9f21b9cceaf258 +size 92738 diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/plain.png b/packages/react-ui/.creevey/images/Input/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/plain.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/plain.png rename to packages/react-ui/.creevey/images/Input/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/plain.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/typed.png b/packages/react-ui/.creevey/images/Input/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/typed.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/typed.png rename to packages/react-ui/.creevey/images/Input/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/typed.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/plain.png b/packages/react-ui/.creevey/images/Input/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/plain.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/plain.png rename to packages/react-ui/.creevey/images/Input/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/plain.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/typed.png b/packages/react-ui/.creevey/images/Input/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/typed.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/typed.png rename to packages/react-ui/.creevey/images/Input/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/typed.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/ie11/plain.png b/packages/react-ui/.creevey/images/Input/Uncontrolled Input with Placeholder/PlainAndTyped/ie11/plain.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/ie11/plain.png rename to packages/react-ui/.creevey/images/Input/Uncontrolled Input with Placeholder/PlainAndTyped/ie11/plain.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/ie11/typed.png b/packages/react-ui/.creevey/images/Input/Uncontrolled Input with Placeholder/PlainAndTyped/ie11/typed.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/ie11/typed.png rename to packages/react-ui/.creevey/images/Input/Uncontrolled Input with Placeholder/PlainAndTyped/ie11/typed.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/blured.png b/packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/blured.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/blured.png rename to packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/blured.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/edited.png b/packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/edited.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/edited.png rename to packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/edited.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/focused.png b/packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/focused.png rename to packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/idle.png b/packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/idle.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/idle.png rename to packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/chrome/idle.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/blured.png b/packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/blured.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/blured.png rename to packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/blured.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/edited.png b/packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/edited.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/edited.png rename to packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/edited.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/focused.png b/packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/focused.png rename to packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/idle.png b/packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/idle.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/idle.png rename to packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/firefox/idle.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/blured.png b/packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/blured.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/blured.png rename to packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/blured.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/edited.png b/packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/edited.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/edited.png rename to packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/edited.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/focused.png b/packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/focused.png rename to packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/idle.png b/packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/idle.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/idle.png rename to packages/react-ui/.creevey/images/Input/With Mask And Custom Unmasked Value/idle, focus, edit, blur/ie11/idle.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Select All Prop/PlainAndSelected/chrome/plain.png b/packages/react-ui/.creevey/images/Input/With Mask And Select All Prop/PlainAndSelected/chrome/plain.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Select All Prop/PlainAndSelected/chrome/plain.png rename to packages/react-ui/.creevey/images/Input/With Mask And Select All Prop/PlainAndSelected/chrome/plain.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Select All Prop/PlainAndSelected/chrome/selectAllFilledInput.png b/packages/react-ui/.creevey/images/Input/With Mask And Select All Prop/PlainAndSelected/chrome/selectAllFilledInput.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Select All Prop/PlainAndSelected/chrome/selectAllFilledInput.png rename to packages/react-ui/.creevey/images/Input/With Mask And Select All Prop/PlainAndSelected/chrome/selectAllFilledInput.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Select All Prop/PlainAndSelected/chrome/selectAllHalfFilledInput.png b/packages/react-ui/.creevey/images/Input/With Mask And Select All Prop/PlainAndSelected/chrome/selectAllHalfFilledInput.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask And Select All Prop/PlainAndSelected/chrome/selectAllHalfFilledInput.png rename to packages/react-ui/.creevey/images/Input/With Mask And Select All Prop/PlainAndSelected/chrome/selectAllHalfFilledInput.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/chrome/blured.png b/packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/chrome/blured.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/chrome/blured.png rename to packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/chrome/blured.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/chrome/edited.png b/packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/chrome/edited.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/chrome/edited.png rename to packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/chrome/edited.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/chrome/focused.png b/packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/chrome/focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/chrome/focused.png rename to packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/chrome/focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/chrome/idle.png b/packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/chrome/idle.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/chrome/idle.png rename to packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/chrome/idle.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/firefox/blured.png b/packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/firefox/blured.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/firefox/blured.png rename to packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/firefox/blured.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/firefox/edited.png b/packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/firefox/edited.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/firefox/edited.png rename to packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/firefox/edited.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/firefox/focused.png b/packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/firefox/focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/firefox/focused.png rename to packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/firefox/focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/firefox/idle.png b/packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/firefox/idle.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/firefox/idle.png rename to packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/firefox/idle.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/ie11/blured.png b/packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/ie11/blured.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/ie11/blured.png rename to packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/ie11/blured.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/ie11/edited.png b/packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/ie11/edited.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/ie11/edited.png rename to packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/ie11/edited.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/ie11/focused.png b/packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/ie11/focused.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/ie11/focused.png rename to packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/ie11/focused.png diff --git a/packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/ie11/idle.png b/packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/ie11/idle.png similarity index 100% rename from packages/react-ui/.creevey/images/Input/Functional tests/With Mask/idle, focus, edit, blur/ie11/idle.png rename to packages/react-ui/.creevey/images/Input/With Mask/idle, focus, edit, blur/ie11/idle.png diff --git a/packages/react-ui/components/Input/__creevey__/Input.creevey.ts b/packages/react-ui/components/Input/__creevey__/Input.creevey.ts new file mode 100644 index 00000000000..cda7e51c2f6 --- /dev/null +++ b/packages/react-ui/components/Input/__creevey__/Input.creevey.ts @@ -0,0 +1,233 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +const differentStatesTest = () => { + test('Plain', async function () { + const element = await this.browser.findElement({ css: '#input' }); + await this.expect(await element.takeScreenshot()).to.matchImage('Plain'); + }); + + test('Focused', async function () { + const element = await this.browser.findElement({ css: '#input' }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#input input' })) + .pause(500) + .perform(); + await this.expect(await element.takeScreenshot()).to.matchImage('Focused'); + }); + + test('With typed text', async function () { + const element = await this.browser.findElement({ css: '#input' }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#input input' })) + .sendKeys('Test...') + .pause(500) + .perform(); + await this.expect(await element.takeScreenshot()).to.matchImage('With typed text'); + }); + + test('With long typed text', async function () { + const element = await this.browser.findElement({ css: '#input' }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#input input' })) + .sendKeys('Test...') + .sendKeys('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') + .pause(500) + .perform(); + await this.expect(await element.takeScreenshot()).to.matchImage('With long typed text'); + }); +}; + +const testMaskedInput = () => { + test('idle, focus, edit, blur', async function () { + const click = (css: string) => { + return this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css })); + }; + const idle = await this.takeScreenshot(); + await click('input').pause(500).perform(); + const focused = await this.takeScreenshot(); + await click('input').sendKeys('953').perform(); + const edited = await this.takeScreenshot(); + await click('body').perform(); + const blured = await this.takeScreenshot(); + await this.expect({ idle, focused, edited, blured }).to.matchImages(); + }); +}; + +kind('Input', () => { + story('Default', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + differentStatesTest(); + }); + + story('WithMask', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + testMaskedInput(); + }); + + story('WithMaskAndCustomUnmaskedValue', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + "themes don't affect logic": { in: /^(?!\bchrome\b)/ }, + }, + }); + + testMaskedInput(); + }); + + story('SelectAllByProp', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + test('Plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); + }); + + test('Focused', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'label' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('Focused'); + }); + }); + + story('SelectAllByButton', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + test('Plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); + }); + + test('Selected', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="select-all"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('Selected'); + }); + }); + + story('MaxLength', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + differentStatesTest(); + }); + + story('UncontrolledInputWithPlaceholder', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + test('PlainAndTyped', async function () { + const plain = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'input' })) + .sendKeys('text') + .perform(); + const typed = await this.takeScreenshot(); + await this.expect({ plain, typed }).to.matchImages(); + }); + }); + + story('WithMaskAndSelectAllProp', ({ setStoryParameters }) => { + setStoryParameters({ skip: { "themes don't affect logic": { in: /^(?!\bchrome\b)/ } } }); + + test('PlainAndSelected', async function () { + const plain = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'input' })) + .pause(500) + .perform(); + const selectAllHalfFilledInput = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'input' })) + .sendKeys('1111') + .click(this.browser.findElement({ css: 'body' })) + .click(this.browser.findElement({ css: 'input' })) + .pause(500) + .perform(); + const selectAllFilledInput = await this.takeScreenshot(); + await this.expect({ plain, selectAllHalfFilledInput, selectAllFilledInput }).to.matchImages(); + }); + }); + + story('SearchTypeApi', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'tests only stable in chrome': { in: /^(?!\bchrome\b|\bchromeDark\b)/ }, + }, + }); + + test('Focused', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'label' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('Focused'); + }); + }); + + story('InputTypeApi', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b|\bchromeDark\b|\bfirefoxDark\b)/ }, + }, + }); + + test('Focused', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'label' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('Focused'); + }); + }); + story('Type', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } }, + }); + }); + story('TypeApi', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } }, + }); + }); +}); diff --git a/packages/react-ui/components/Input/__stories__/Input.stories.tsx b/packages/react-ui/components/Input/__stories__/Input.stories.tsx new file mode 100644 index 00000000000..a197bc9ca74 --- /dev/null +++ b/packages/react-ui/components/Input/__stories__/Input.stories.tsx @@ -0,0 +1,459 @@ +// TODO: Rewrite stories and enable rule (in process of functional refactoring). +/* eslint-disable react/no-unstable-nested-components */ +import React, { useState } from 'react'; +import SearchIcon from '@skbkontur/react-icons/Search'; + +import { ComponentTable } from '../../../internal/ComponentTable'; +import { Meta, Story } from '../../../typings/stories'; +import { Input, InputProps } from '../Input'; +import { Gapped } from '../../Gapped'; + +export default { + title: 'Input', +} as Meta; + +type InputState = Partial; + +const sizeStates: InputState[] = [{ size: 'small' }, { size: 'medium' }, { size: 'large' }]; + +const inputDefaultState: InputState[] = [{}, { defaultValue: 'Value' }]; + +const inputWidthStates: InputState[] = [{}, { width: '100px' }, { width: '350px' }]; + +export const Align: Story = () => ( + ({ props: x }))} + rows={alignDifferentStates.map((x) => ({ props: x }))} + presetProps={{ value: 'Value', width: '200px' }} + /> +); + +const alignStates: InputState[] = [{ align: 'center' }, { align: 'left' }, { align: 'right' }]; + +const alignDifferentStates: InputState[] = [ + {}, + { leftIcon: }, + { rightIcon: }, + { prefix: 'PR' }, + { suffix: 'SF' }, + { leftIcon: , prefix: 'PR' }, + { leftIcon: , suffix: 'SF' }, + { rightIcon: , prefix: 'PR' }, + { rightIcon: , suffix: 'SF' }, + { leftIcon: , prefix: 'PR', suffix: 'SF' }, + { rightIcon: , prefix: 'PR', suffix: 'SF' }, +]; + +export const AlwaysShowMask: Story = () => ( + ({ props: x }))} + rows={alwaysShowMaskStates.map((x) => ({ props: x }))} + presetProps={{ mask: '(***) ***-**-**' }} + /> +); + +const alwaysShowMaskStates: InputState[] = [ + {}, + { defaultValue: '95678901' }, + { defaultValue: '956789010A' }, + { alwaysShowMask: true }, + { alwaysShowMask: true, defaultValue: '95678901' }, + { alwaysShowMask: true, defaultValue: '956789010A' }, +]; + +export const Borderless: Story = () => ( + ({ props: x }))} + rows={borderlessStates.map((x) => ({ props: x }))} + presetProps={{ borderless: true }} + /> +); + +const borderlessStates: InputState[] = [{}]; + +export const Disabled: Story = () => ( + ({ props: x }))} + rows={disabledStates.map((x) => ({ props: x }))} + presetProps={{ disabled: true }} + /> +); + +const disabledStates: InputState[] = [ + {}, + { value: 'Some text' }, + { placeholder: 'Placeholder' }, + { type: 'password', value: 'Value' }, + { leftIcon: }, + { rightIcon: }, + { prefix: 'PR' }, + { suffix: 'SF' }, +]; + +export const Error: Story = () => ( + ({ props: x }))} + rows={errorStates.map((x) => ({ props: x }))} + presetProps={{ error: true }} + /> +); +const errorStates: InputState[] = [{}, { borderless: true }, { disabled: true }]; + +export const LeftIcon: Story = () => ( + ({ props: x }))} + rows={iconsLeftStates.map((x) => ({ props: x }))} + presetProps={{ leftIcon: }} + /> +); + +export const RightIcon: Story = () => ( + ({ props: x }))} + rows={iconsRightStates.map((x) => ({ props: x }))} + presetProps={{ rightIcon: }} + /> +); + +const iconFunc = () => ; +iconFunc.toString = () => '() => '; + +const iconsStates: InputState[] = [{}, { defaultValue: 'Value' }, { disabled: true }]; + +const iconsLeftStates: InputState[] = [ + ...iconsStates, + { + leftIcon: iconFunc, + }, + { + leftIcon: '₽', + }, +]; + +const iconsRightStates: InputState[] = [ + ...iconsStates, + { + rightIcon: iconFunc, + }, + { + rightIcon: '₽', + }, +]; + +export const Mask: Story = () => ( + ({ props: x }))} + rows={maskStates.map((x) => ({ props: x }))} + presetProps={{}} + /> +); + +const maskStates: InputState[] = [ + { mask: '**** **********', alwaysShowMask: true }, + { mask: '**** **********', maskChar: '*', alwaysShowMask: true }, + { mask: '*** ***', maskChar: '_', defaultValue: 'Value' }, + { mask: '*** ***', maskChar: '_', defaultValue: 'Value', alwaysShowMask: true }, + { type: 'email', mask: '*** ***', maskChar: '_', defaultValue: 'Value', alwaysShowMask: true }, + { type: 'tel', mask: '*** ***', maskChar: '_', defaultValue: 'Value', alwaysShowMask: true }, + { type: 'url', mask: '*** ***', maskChar: '_', defaultValue: 'Value', alwaysShowMask: true }, + { type: 'search', mask: '*** ***', maskChar: '_', defaultValue: 'Value', alwaysShowMask: true }, + { type: 'date', mask: '*** ***', maskChar: '_', defaultValue: 'Value', alwaysShowMask: true }, + { type: 'time', mask: '*** ***', maskChar: '_', defaultValue: 'Value', alwaysShowMask: true }, + { type: 'number', mask: '*** ***', maskChar: '_', defaultValue: 'Value', alwaysShowMask: true }, + { mask: '*** ***', placeholder: 'ooo-long-long-long-placeholder' }, +]; + +export const Placeholder: Story = () => ( + ({ props: x }))} + rows={placeholderStates.map((x) => ({ props: x }))} + presetProps={{ placeholder: '1234567890' }} + /> +); + +const placeholderStates: InputState[] = [{}, { disabled: true }]; + +export const Prefix: Story = () => ( + ({ props: x }))} + rows={inputPrefixStates.map((x) => ({ props: x }))} + presetProps={{ prefix: 'Prefix' }} + /> +); +const inputPrefixOrSuffixStates: InputState[] = [ + {}, + { value: 'Value' }, + { placeholder: 'Placeholder' }, + { rightIcon: }, + { rightIcon: , value: 'Value' }, + { rightIcon: , placeholder: 'Placeholder' }, + { leftIcon: }, + { leftIcon: , value: 'Value' }, + { leftIcon: , placeholder: 'Placeholder' }, +]; + +const inputPrefixStates: InputState[] = [...inputPrefixOrSuffixStates, { prefix: 'ooo-long-long-long-johnson' }]; + +const inputSuffixStates: InputState[] = [...inputPrefixOrSuffixStates, { suffix: 'ooo-long-long-long-johnson' }]; + +export const Suffix: Story = () => ( + ({ props: x }))} + rows={inputSuffixStates.map((x) => ({ props: x }))} + presetProps={{ suffix: 'Suffix' }} + /> +); + +export const PrefixAndSuffixBoth: Story = () => ( + ({ props: x }))} + rows={inputPrefixOrSuffixStates.map((x) => ({ props: x }))} + presetProps={{ prefix: 'Prefix', suffix: 'Suffix' }} + /> +); + +export const Size: Story = () => ( + ({ props: x }))} + rows={inputDefaultState.map((x) => ({ props: x }))} + presetProps={{ children: 'Input' }} + /> +); + +export const TextStylesReset: Story = () => ( +
+ + Inherited Styles + + + + + } prefix="Prefix" suffix="suffix" defaultValue="Value" /> + +
+); + +export const Type: Story = () => ( + ({ props: x }))} + rows={typeStates.map((x) => ({ props: x }))} + presetProps={{}} + /> +); + +const typeStates: InputState[] = [ + { type: 'text', defaultValue: 'Value' }, + { type: 'password', defaultValue: 'Value' }, + { type: 'password', defaultValue: 'Value', disabled: true }, + { mask: '***-***', type: 'password', alwaysShowMask: true }, + { mask: '***-***', type: 'password', alwaysShowMask: true, defaultValue: 'Value' }, + { mask: '***-***', type: 'password', alwaysShowMask: true, defaultValue: 'Value', disabled: true }, + { type: 'number', defaultValue: '15', min: 10, max: 20, step: 5 }, + { type: 'search' }, + { type: 'date' }, + { type: 'time' }, + { type: 'email', pattern: '[a-z0-9._%+-]+@[a-z0-9.-]+.[a-z]{2,4}$' }, + { type: 'url' }, + { type: 'tel' }, +]; + +export const TypeApi: Story = () => ( + <> + ({ props: x }))} + rows={typeApiTypes.map((x) => ({ props: x }))} + presetProps={{}} + /> + ({ props: x }))} + rows={typeApiTypesDate.map((x) => ({ props: x }))} + presetProps={{}} + /> + ({ props: x }))} + rows={typeApiTypesTime.map((x) => ({ props: x }))} + presetProps={{}} + /> + +); + +const typeApiTypes: InputState[] = [ + { type: 'number' }, + { type: 'search' }, + { type: 'email' }, + { type: 'url' }, + { type: 'tel' }, +]; +const typeApiTypesDate: InputState[] = [{ type: 'date' }]; +const typeApiTypesTime: InputState[] = [{ type: 'time' }]; + +const typeApiProps: InputState[] = [ + { leftIcon: , value: '123' }, + { rightIcon: , value: '123' }, + { rightIcon: , placeholder: 'placeholder' }, + { prefix: 'prefix: ' }, + { suffix: ' suffix' }, +]; +const typeApiPropsDate: InputState[] = [ + { rightIcon: }, + { leftIcon: }, + { value: '2022-05-04' }, + { prefix: 'prefix: ' }, + { suffix: ' suffix' }, +]; +const typeApiPropsTime: InputState[] = [ + { rightIcon: }, + { leftIcon: }, + { value: '18:00' }, + { prefix: 'prefix: ' }, + { suffix: ' suffix' }, +]; + +export const Warning: Story = () => ( + ({ props: x }))} + rows={warningStates.map((x) => ({ props: x }))} + presetProps={{ warning: true }} + /> +); + +const warningStates: InputState[] = [{}, { borderless: true }, { disabled: true }]; + +export const BlinkingByButton: Story = () => { + class Sample extends React.Component { + private input: Input | null = null; + + public render() { + return ( + + + + + ); + } + + private handleClick = () => { + if (this.input) { + this.input.blink(); + } + }; + + private refInput = (element: Input | null) => { + this.input = element; + }; + } + + return ; +}; +BlinkingByButton.parameters = { creevey: { skip: true } }; + +export const Default: Story = () => ( +
+ +
+); + +export const WithMask: Story = () => ( + +); + +export const WithMaskAndCustomUnmaskedValue: Story = () => { + const [value, setValue] = useState('+795'); + + return ( + setValue(value.replace(/\s/g, ''))} + /> + ); +}; + +export const SelectAllByProp: Story = () => ; + +export const SelectAllByButton: Story = () => { + let input: Input | null = null; + + const selectAll = () => { + if (input) { + input.selectAll(); + } + }; + + return ( +
+
+ (input = element)} defaultValue="Some value" /> +
+ +
+ ); +}; +SelectAllByButton.storyName = 'Select all by button'; + +export const MaxLength: Story = () => ( +
+ +
+); + +export const UncontrolledInputWithPlaceholder: Story = () => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [_value, setValue] = React.useState(); + return setValue(value)} />; +}; +UncontrolledInputWithPlaceholder.storyName = 'Uncontrolled Input with Placeholder'; + +export const WithMaskAndSelectAllProp: Story = () => { + const inputRef = React.useRef(null); + const [value, setValue] = React.useState('11'); + const selectAll = React.useCallback(() => { + inputRef.current?.selectAll(); + }, [inputRef.current]); + return ( +
+ +
+ ); +}; + +export const SearchTypeApi: Story = () => ; + +export const InputTypeApi: Story = () => ; From 16d302fb34c717b2e9bfece39ec57fc2a93786e9 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Tue, 14 May 2024 12:33:01 +0500 Subject: [PATCH 037/197] chore: fix Kebab test --- .../opened/chrome/opened.png | 3 - .../opened/chrome/opened.png | 3 - .../opened/chrome/opened.png | 3 + .../opened/chrome/opened.png | 3 + .../Kebab/__creevey__/Kebab.creevey.ts | 169 ++++++++++++++++++ .../Kebab/__stories__/Kebab.items.tsx | 53 ++++++ .../Kebab/__stories__/Kebab.stories.tsx | 144 +++++++++++++++ 7 files changed, 372 insertions(+), 6 deletions(-) delete mode 100644 packages/react-ui/.creevey/images/Kebab/Functional tests/With Items And Icons Without Text Alignment/opened/chrome/opened.png delete mode 100644 packages/react-ui/.creevey/images/Kebab/Functional tests/With Items And Icons/opened/chrome/opened.png create mode 100644 packages/react-ui/.creevey/images/Kebab/With Items And Icons Without Text Alignment/opened/chrome/opened.png create mode 100644 packages/react-ui/.creevey/images/Kebab/With Items And Icons/opened/chrome/opened.png create mode 100644 packages/react-ui/components/Kebab/__creevey__/Kebab.creevey.ts create mode 100644 packages/react-ui/components/Kebab/__stories__/Kebab.items.tsx create mode 100644 packages/react-ui/components/Kebab/__stories__/Kebab.stories.tsx diff --git a/packages/react-ui/.creevey/images/Kebab/Functional tests/With Items And Icons Without Text Alignment/opened/chrome/opened.png b/packages/react-ui/.creevey/images/Kebab/Functional tests/With Items And Icons Without Text Alignment/opened/chrome/opened.png deleted file mode 100644 index d6eaefeb764..00000000000 --- a/packages/react-ui/.creevey/images/Kebab/Functional tests/With Items And Icons Without Text Alignment/opened/chrome/opened.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d09ae5eee80b85bb8c47f379f7246f6d571066d8ea75578dcc33d270d124200c -size 6638 diff --git a/packages/react-ui/.creevey/images/Kebab/Functional tests/With Items And Icons/opened/chrome/opened.png b/packages/react-ui/.creevey/images/Kebab/Functional tests/With Items And Icons/opened/chrome/opened.png deleted file mode 100644 index 41e877ec69e..00000000000 --- a/packages/react-ui/.creevey/images/Kebab/Functional tests/With Items And Icons/opened/chrome/opened.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cc9058873ff2de9f1174cc196284b10c78890442f0b0d86a1c838cbd4b912278 -size 6636 diff --git a/packages/react-ui/.creevey/images/Kebab/With Items And Icons Without Text Alignment/opened/chrome/opened.png b/packages/react-ui/.creevey/images/Kebab/With Items And Icons Without Text Alignment/opened/chrome/opened.png new file mode 100644 index 00000000000..4ab7ab9a778 --- /dev/null +++ b/packages/react-ui/.creevey/images/Kebab/With Items And Icons Without Text Alignment/opened/chrome/opened.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fc8306f0b19a313ba1de7e73cf6e2b6ec3caa156e9effc25da0b88b926b5cd53 +size 5433 diff --git a/packages/react-ui/.creevey/images/Kebab/With Items And Icons/opened/chrome/opened.png b/packages/react-ui/.creevey/images/Kebab/With Items And Icons/opened/chrome/opened.png new file mode 100644 index 00000000000..724b8fad5dc --- /dev/null +++ b/packages/react-ui/.creevey/images/Kebab/With Items And Icons/opened/chrome/opened.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ccf899da35555497dee06a32becee145f65362cc4b8e9869afec6aa8b0943dd2 +size 5433 diff --git a/packages/react-ui/components/Kebab/__creevey__/Kebab.creevey.ts b/packages/react-ui/components/Kebab/__creevey__/Kebab.creevey.ts new file mode 100644 index 00000000000..23dfb612b90 --- /dev/null +++ b/packages/react-ui/components/Kebab/__creevey__/Kebab.creevey.ts @@ -0,0 +1,169 @@ +import { story, kind, test } from 'creevey'; +import { PopupMenuDataTids } from '../../../internal/PopupMenu'; + +import { delay } from '../../../lib/utils'; +const textAlignmentTests = () => { + test('opened', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: `[data-tid~="${PopupMenuDataTids.caption}"]` })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); +}; + +const kebabTests = () => { + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('hovered', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: '[data-comp-name~="Kebab"]' }), + }) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); + }); + + test('clicked', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Kebab"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); + }); + + test('clickedOnButton2ndTime', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Kebab"]' })) + .click(this.browser.findElement({ css: '[data-comp-name~="Kebab"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('clickedOnButton2ndTime'); + }); + + test('tabPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); + }); + + test('enterPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .sendKeys(this.keys.ENTER) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('enterPress'); + }); +}; + +kind('Kebab', () => { + story('Small', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'hovered' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'clickedOnButton2ndTime'], + }, + }, + }); + + kebabTests(); + }); + + story('Medium', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'hovered' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'clickedOnButton2ndTime'], + }, + }, + }); + + kebabTests(); + }); + + story('Large', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'hovered' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'clickedOnButton2ndTime'], + }, + }, + }); + + kebabTests(); + }); + + story('KebabHintRemovePinFeatureFlag', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: /^(?!\b.*2022.*\b)/ }, + 'story-skip-1': { + in: /(?!\b.*2022.*\b)/, + tests: ['plain', 'hovered', 'clickedOnButton2ndTime', 'tabPress', 'enterPress'], + }, + }, + }); + + kebabTests(); + }); + + story('MobileExampleWithHorizontalPadding', ({ setStoryParameters }) => { + setStoryParameters({ captureElement: null }); + + test('opened', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-comp-name~="Kebab"]' })) + .perform(); + await delay(200); + await this.browser + .actions({ bridge: true }) + .move({ origin: this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' }) }) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); + }); + story('WithItemsAndIcons', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }); + + textAlignmentTests(); + }); + + story('WithItemsAndIconsWithoutTextAlignment', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }); + + textAlignmentTests(); + }); +}); diff --git a/packages/react-ui/components/Kebab/__stories__/Kebab.items.tsx b/packages/react-ui/components/Kebab/__stories__/Kebab.items.tsx new file mode 100644 index 00000000000..f79ea3bb1a7 --- /dev/null +++ b/packages/react-ui/components/Kebab/__stories__/Kebab.items.tsx @@ -0,0 +1,53 @@ +export const defaultItemsList = [ + { + text: 'First', + action: 'First', + }, + { + text: 'Second', + action: 'Second', + }, + { + text: 'Uno', + action: 'Uno', + }, +]; + +export const manyItemsList = [ + { + text: 'Edit', + action: 'Edit', + }, + { + text: 'Remove', + action: 'Remove', + }, + { + text: 'Communicate', + action: 'Communicate', + }, + { + text: 'Grade', + action: 'Grade', + }, + { + text: 'Dispatch', + action: 'Dispatch', + }, + { + text: 'Disable', + action: 'Disable', + }, + { + text: 'Rate', + action: 'Rate', + }, + { + text: 'Collaborate', + action: 'Collaborate', + }, + { + text: 'Contribute', + action: 'Contribute', + }, +]; diff --git a/packages/react-ui/components/Kebab/__stories__/Kebab.stories.tsx b/packages/react-ui/components/Kebab/__stories__/Kebab.stories.tsx new file mode 100644 index 00000000000..718bafcaf7c --- /dev/null +++ b/packages/react-ui/components/Kebab/__stories__/Kebab.stories.tsx @@ -0,0 +1,144 @@ +import React from 'react'; +import { action } from '@storybook/addon-actions'; +import OkIcon from '@skbkontur/react-icons/Ok'; + +import { ReactUIFeatureFlagsContext } from '../../../lib/featureFlagsContext'; +import { Meta, Story } from '../../../typings/stories'; +import { Kebab } from '../Kebab'; +import { MenuItem } from '../../MenuItem'; +import { KebabProps } from '..'; +import { MenuHeader } from '../../MenuHeader'; + +import { defaultItemsList, manyItemsList } from './Kebab.items'; + +interface KebabItem { + text: string; + action: string; +} + +export default { + title: 'Kebab', + decorators: [ + (Story: () => JSX.Element) => ( +
+ +
+ ), + ], +} as Meta; + +export const Small: Story = () => ; +Small.storyName = '14px'; + +export const Medium: Story = () => ; +Medium.storyName = '18px'; + +export const Large: Story = () => ; +Large.storyName = '20px'; + +export const KebabHintRemovePinFeatureFlag: Story = () => { + return ( + + + + ); +}; +KebabHintRemovePinFeatureFlag.storyName = 'with kebabHintRemovePin feature flag'; + +export const KebabWithCustomIcon: Story = () => { + return ( + <> + } /> + } /> + } /> + + ); +}; + +export const LargeDisabled = () => ; +LargeDisabled.storyName = '20px-disabled'; +LargeDisabled.parameters = { creevey: { skip: true } }; + +export const WithFixedMenuHeight = () => ( + +); +WithFixedMenuHeight.storyName = 'With fixed menu height'; +WithFixedMenuHeight.parameters = { creevey: { skip: true } }; + +export const KebabWithoutAnimations = () => ; +KebabWithoutAnimations.storyName = 'Kebab without animations'; +KebabWithoutAnimations.parameters = { creevey: { skip: true } }; + +interface SomethingWithKebabProps { + items?: KebabItem[]; + disableAnimations?: boolean; + size: KebabProps['size']; + disabled?: boolean; + menuMaxHeight?: number | string; + icon?: React.ReactNode; +} +class SomethingWithKebab extends React.Component { + public render() { + const itemsList = this.props.items || defaultItemsList; + const menuItems = itemsList.map((item: KebabItem, index: number) => { + return ( + + {item.text} + + ); + }); + + return ( +
+ Pikachu{' '} + + {menuItems} + +
+ ); + } +} + +export const MobileExampleWithHorizontalPadding: Story = () => ; + +MobileExampleWithHorizontalPadding.parameters = { + viewport: { + defaultViewport: 'iphone', + }, +}; + +export const WithItemsAndIcons: Story = () => ( +
+ + MenuHeader + }>MenuItem1 + }>MenuItem2 + MenuItem3 + +
+); + +export const WithItemsAndIconsWithoutTextAlignment = () => ( +
+ + MenuHeader + }>MenuItem1 + }>MenuItem2 + MenuItem3 + +
+); From 753dcfecd616e85a7934e5e2c436b42b3d91cea5 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Tue, 14 May 2024 12:43:29 +0500 Subject: [PATCH 038/197] chore: fix Link test --- .../Link/__creevey__/Link.creevey.ts | 162 ++++++++++++++++++ .../Link/__stories__/Link.stories.tsx | 101 +++++++++++ 2 files changed, 263 insertions(+) create mode 100644 packages/react-ui/components/Link/__creevey__/Link.creevey.ts create mode 100644 packages/react-ui/components/Link/__stories__/Link.stories.tsx diff --git a/packages/react-ui/components/Link/__creevey__/Link.creevey.ts b/packages/react-ui/components/Link/__creevey__/Link.creevey.ts new file mode 100644 index 00000000000..db610e56dd1 --- /dev/null +++ b/packages/react-ui/components/Link/__creevey__/Link.creevey.ts @@ -0,0 +1,162 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +const focusedLinkTest = () => { + test('tab press', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: 'a' }), + }) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPressHovered'); + }); +}; +const linkTests = () => { + test('idle', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('idle'); + }); + + test('hover', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: 'a' }), + }) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('hover'); + }); +}; + +const focusedStyledLinkTest = () => { + test('tab press', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: 'a' }), + }) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: 'a' }), + }) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPressHovered'); + }); +}; + +kind('Link', () => { + story('Simple', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + // TODO @Khlutkova fix after update browsers + 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, + }, + }); + + linkTests(); + }); + + story('WithIcon', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + // TODO @Khlutkova fix after update browsers + 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, + 'story-skip-1': { in: /^(?!\b(chrome|firefox)(2022)*(Dark)*\b)/, tests: ['tab press'] }, + }, + }); + + linkTests(); + focusedLinkTest(); + }); + + story('Danger', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + // TODO @Khlutkova fix after update browsers + 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, + }, + }); + + linkTests(); + }); + + story('Grayed', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + // TODO @Khlutkova fix after update browsers + 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, + }, + }); + + linkTests(); + }); + + story('Disabled', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + // TODO @Khlutkova fix after update browsers + 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, + }, + }); + + linkTests(); + }); + + story('Loading', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + // TODO @Khlutkova fix after update browsers + 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, + }, + }); + + linkTests(); + }); + + story('FocusedStyledLink', ({ setStoryParameters }) => { + setStoryParameters({ skip: { flacky: { in: /^(?!\b(firefox2022)\b)/ } } }); + + focusedStyledLinkTest(); + }); + + story('WithLinkFocusOutlineFeatureFlag', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'hover does not work': { + in: /chrome/, + }, + }, + }); + + focusedStyledLinkTest(); + }); +}); diff --git a/packages/react-ui/components/Link/__stories__/Link.stories.tsx b/packages/react-ui/components/Link/__stories__/Link.stories.tsx new file mode 100644 index 00000000000..2f9012f1d26 --- /dev/null +++ b/packages/react-ui/components/Link/__stories__/Link.stories.tsx @@ -0,0 +1,101 @@ +import React from 'react'; +import OkIcon from '@skbkontur/react-icons/Ok'; +import { CheckAIcon16Light } from '@skbkontur/icons/icons/CheckAIcon'; + +import { Story } from '../../../typings/stories'; +import { Link } from '../Link'; +import { Toast } from '../../Toast'; +import { Gapped } from '../../Gapped'; +import { ThemeContext } from '../../../lib/theming/ThemeContext'; +import { ThemeFactory } from '../../../lib/theming/ThemeFactory'; +import { ReactUIFeatureFlagsContext } from '../../../lib/featureFlagsContext'; + +export default { + title: 'Link', + parameters: { + creevey: { + skip: { + 'kind-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'hover' }, + }, + }, + }, +}; + +export const Simple: Story = () => Simple Link; + +export const WithIcon: Story = () => { + return ( + + + }>Left Icon Link + } rightIcon={}> + Both Icons Link + + }>Right Icon Link + + + }> + Left Icon Link + + } rightIcon={}> + Both Icons Link + + }> + Right Icon Link + + + + ); +}; + +export const Danger: Story = () => ( + } use="danger"> + Simple Link + +); + +export const Grayed: Story = () => Simple link; + +export const Disabled: Story = () => Simple link; + +export const WithOnClick = () => Toast.push('Clicked!')}>Simple Link; +WithOnClick.storyName = 'With onClick'; +WithOnClick.parameters = { creevey: { skip: true } }; + +export const Loading: Story = () => ( + + Simple loading +
+ {'Some long text '} + loading link + and end of line +
+
+ {'Some long text '} + loading link + and end of line +
+ }> + Loading link with icon + +
+); +export const FocusedStyledLink: Story = () => { + return ( + + {(theme) => { + return ( + + }>Simple Link + + ); + }} + + ); +}; + +export const WithLinkFocusOutlineFeatureFlag = () => ( + + Link + +); From cd2ed4b330d7efe87082da73de3758864954b63a Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Tue, 14 May 2024 12:49:37 +0500 Subject: [PATCH 039/197] chore: fix Loader test --- .../Loader/__creevey__/Loader.creevey.ts | 34 ++ .../Loader/__stories__/Loader.stories.tsx | 321 ++++++++++++++++++ .../Loader/__stories__/LoaderAndButton.tsx | 57 ++++ 3 files changed, 412 insertions(+) create mode 100644 packages/react-ui/components/Loader/__creevey__/Loader.creevey.ts create mode 100644 packages/react-ui/components/Loader/__stories__/Loader.stories.tsx create mode 100644 packages/react-ui/components/Loader/__stories__/LoaderAndButton.tsx diff --git a/packages/react-ui/components/Loader/__creevey__/Loader.creevey.ts b/packages/react-ui/components/Loader/__creevey__/Loader.creevey.ts new file mode 100644 index 00000000000..c908d6252b8 --- /dev/null +++ b/packages/react-ui/components/Loader/__creevey__/Loader.creevey.ts @@ -0,0 +1,34 @@ +import { story, kind, test } from 'creevey'; + +kind('Loader', () => { + story('ActiveLoader', () => { + test('covers children', async function () { + const element = await this.browser.findElement({ css: '[data-comp-name~="Loader"]' }); + const button = await this.browser.findElement({ css: '[data-comp-name~="Button"]' }); + await this.browser.actions({ bridge: true }).click(button).perform(); + await this.expect(await element.takeScreenshot()).to.matchImage('cover children'); + }); + }); + + story('InactiveLoader', () => { + test("doesn't cover children", async function () { + const element = await this.browser.findElement({ css: '[data-comp-name~="Loader"]' }); + const button = await this.browser.findElement({ css: '[data-comp-name~="Button"]' }); + await this.browser.actions({ bridge: true }).click(button).perform(); + await this.expect(await element.takeScreenshot()).to.matchImage("doesn't cover children"); + }); + }); + + story('FocusInside', () => { + test('focus inside', async function () { + const loader = await this.browser.findElement({ css: '[data-comp-name~="Loader"]' }); + const toggle = await this.browser.findElement({ css: '[data-tid~="toggle-loader"]' }); + await this.browser.actions().sendKeys(this.keys.TAB).perform(); + const enabled = await loader.takeScreenshot(); + await this.browser.actions().click(toggle).move({ x: 0, y: 0 }).click().perform(); + await this.browser.actions().sendKeys(this.keys.TAB).perform(); + const disabled = await loader.takeScreenshot(); + await this.expect({ enabled, disabled }).to.matchImages(); + }); + }); +}); diff --git a/packages/react-ui/components/Loader/__stories__/Loader.stories.tsx b/packages/react-ui/components/Loader/__stories__/Loader.stories.tsx new file mode 100644 index 00000000000..599ca3d4db7 --- /dev/null +++ b/packages/react-ui/components/Loader/__stories__/Loader.stories.tsx @@ -0,0 +1,321 @@ +import React, { useState } from 'react'; + +import { AnyObject } from '../../../lib/utils'; +import { Story } from '../../../typings/stories'; +import { Loader, LoaderProps } from '../Loader'; +import { css } from '../../../lib/theming/Emotion'; +import { EyeOpenedIcon } from '../../../internal/icons/16px/index'; +import { ThemeContext } from '../../../lib/theming/ThemeContext'; +import { Toggle } from '../../Toggle'; + +import { LoaderAndButton } from './LoaderAndButton'; + +const loaderClass = css` + height: 100%; +`; + +const wrapperStyle = { + width: '800px', + background: 'AliceBlue', +}; + +const darkWrapperStyle = { + ...wrapperStyle, + background: '#1f1f1f', +}; + +interface ContentComponentProps { + additionalStyle?: AnyObject; + loaderProps?: Partial; +} +class ContentComponent extends React.Component> { + public render() { + const { additionalStyle, loaderProps, children } = this.props; + return ( + + {(theme) => { + return ( +
+ + {children} + +
+ ); + }} +
+ ); + } +} + +interface NumberListProps { + itemsCount: number; +} +class NumberList extends React.Component { + public render() { + return ( + <> + {this.getItems(this.props.itemsCount).map((i) => ( +
{i}
+ ))} + + ); + } + + private getItems(count: number) { + const items = []; + for (let i = 0; i < count; i += 1) { + items.push(i); + } + return items; + } +} + +export default { title: 'Loader' }; + +export const Simple = () => { + const [toggleValue, setToggleValue] = useState(false); + return ( + <> + setToggleValue(v)} /> + +
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut + labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut + aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore + eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt + mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor + incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco + laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit + esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui + officia deserunt mollit anim id est laborum. +
+
+ + ); +}; +Simple.parameters = { creevey: { skip: true } }; + +export const TypeBig = () => ( + + + +); +TypeBig.storyName = 'Type "big"'; +TypeBig.parameters = { creevey: { skip: true } }; + +export const TypeBigWithText = () => ( +
+

+ Yeah, and if you were the pope they'd be all, "Straighten your pope hat." And "Put on your + good vestments." +

+

+ No, I'm Santa Claus! I guess if you want children beaten, you have to do it yourself. We're also Santa + Claus! Leela, Bender, we're going grave robbing. +

+

+ Are you crazy? I can't swallow that. Large bet on myself in round one. Hey, whatcha watching?{' '} + Moving along… I guess if you want children beaten, you have to do it yourself. + It's okay, Bender. I like cooking too. +

+

Oh, I think we should just stay friends.

+

+ No argument here. And when we woke up, we had these bodies. You guys go on without me! I'm going to go… look + for more stuff to steal! Oh, how awful. Did he at least die painlessly? …To shreds, you say. Well, how is his wife + holding up? …To shreds, you say. +

+
    +
  1. No! The kind with looting and maybe starting a few fires!
  2. +
  3. You are the last hope of the universe.
  4. +
  5. Hey, guess what you're accessories to.
  6. +
+ +

+ Yeah, and if you were the pope they'd be all, "Straighten your pope hat." And "Put on your + good vestments." +

+

+ No, I'm Santa Claus! I guess if you want children beaten, you have to do it yourself. We're also Santa + Claus! Leela, Bender, we're going grave robbing. +

+

+ Are you crazy? I can't swallow that. Large bet on myself in round one. Hey, whatcha watching?{' '} + Moving along… I guess if you want children beaten, you have to do it yourself. + It's okay, Bender. I like cooking too. +

+

Oh, I think we should just stay friends.

+

+ No argument here. And when we woke up, we had these bodies. You guys go on without me! I'm going to go… + look for more stuff to steal! Oh, how awful. Did he at least die painlessly? …To shreds, you say. Well, how is + his wife holding up? …To shreds, you say. +

+
    +
  1. No! The kind with looting and maybe starting a few fires!
  2. +
  3. You are the last hope of the universe.
  4. +
  5. Hey, guess what you're accessories to.
  6. +
+
+

+ Yeah, and if you were the pope they'd be all, "Straighten your pope hat." And "Put on your + good vestments." +

+

+ No, I'm Santa Claus! I guess if you want children beaten, you have to do it yourself. We're also Santa + Claus! Leela, Bender, we're going grave robbing. +

+

+ Are you crazy? I can't swallow that. Large bet on myself in round one. Hey, whatcha watching?{' '} + Moving along… I guess if you want children beaten, you have to do it yourself. + It's okay, Bender. I like cooking too. +

+

Oh, I think we should just stay friends.

+

+ No argument here. And when we woke up, we had these bodies. You guys go on without me! I'm going to go… look + for more stuff to steal! Oh, how awful. Did he at least die painlessly? …To shreds, you say. Well, how is his wife + holding up? …To shreds, you say. +

+
    +
  1. No! The kind with looting and maybe starting a few fires!
  2. +
  3. You are the last hope of the universe.
  4. +
  5. Hey, guess what you're accessories to.
  6. +
+
+); +TypeBigWithText.storyName = 'Type "big" with text'; +TypeBigWithText.parameters = { creevey: { skip: true } }; + +export const VerticalScroll = () => ( + + + +); +VerticalScroll.storyName = 'Vertical scroll'; +VerticalScroll.parameters = { creevey: { skip: true } }; + +export const HorizontalScroll = () => ( + + + +); +HorizontalScroll.storyName = 'Horizontal scroll'; +HorizontalScroll.parameters = { creevey: { skip: true } }; + +export const BothDimensionsScrollableContentWithSpacesAround = () => ( + + + +); +BothDimensionsScrollableContentWithSpacesAround.storyName = 'Both dimensions scrollable content with spaces around'; +BothDimensionsScrollableContentWithSpacesAround.parameters = { creevey: { skip: true } }; + +export const ActiveLoader: Story = () => ; +ActiveLoader.storyName = 'Active loader'; + +export const InactiveLoader: Story = () => ; +InactiveLoader.storyName = 'Inactive loader'; + +export const WrapperWithCustomHeightAndInactiveLoader = () => ( + + {(theme) => { + return ( + +
+ +
+
+ ); + }} +
+); +WrapperWithCustomHeightAndInactiveLoader.storyName = 'Wrapper with custom height and inactive loader'; + +export const WrapperWithCustomHeightAndActiveLoader = () => ( + + {(theme) => { + return ( + +
+ +
+
+ ); + }} +
+); +WrapperWithCustomHeightAndActiveLoader.storyName = 'Wrapper with custom height and active loader'; + +export const ActivateLoaderAfterMountOnLargeContent = () => { + const [active, setActive] = React.useState(false); + React.useEffect(() => { + setActive(true); + }, []); + + return ( + + + + ); +}; + +export const WithCustomComponent: Story = () => { + const getTestComponent = () => { + return ( +
+ + Загрузка +
+ ); + }; + + const testText = 'Lorem ipsum dolor sit '.repeat(40); + + return ( +
+ + {testText} + +
+ + {testText} + +
+ + {testText} + +
+ ); +}; + +export const FocusInside: Story = () => { + const [active, setActive] = React.useState(false); + return ( +
+ + + + +
+ ); +}; diff --git a/packages/react-ui/components/Loader/__stories__/LoaderAndButton.tsx b/packages/react-ui/components/Loader/__stories__/LoaderAndButton.tsx new file mode 100644 index 00000000000..441146a5b18 --- /dev/null +++ b/packages/react-ui/components/Loader/__stories__/LoaderAndButton.tsx @@ -0,0 +1,57 @@ +import React from 'react'; + +import { Tooltip } from '../../Tooltip'; +import { Button } from '../../Button'; +import { Loader } from '../Loader'; +import { LoaderProps } from '..'; + +type LoaderAndButtonProps = Pick; +interface LoaderAndButtonState { + isTooltipOpened: boolean; + isActive?: boolean; +} +export class LoaderAndButton extends React.Component { + public state: LoaderAndButtonState = { + isTooltipOpened: false, + }; + + public render() { + return ( + +

+ Yeah, and if you were the pope they'd be all, "Straighten your pope hat." And "Put on your + good vestments." +

+ 'Yes, you can!'} trigger={this.state.isTooltipOpened ? 'opened' : 'closed'}> + + +

+ No, I'm Santa Claus! I guess if you want children beaten, you have to do it yourself. We're also + Santa Claus! Leela, Bender, we're going grave robbing. +

+

+ Are you crazy? I can't swallow that. Large bet on myself in round one. Hey, whatcha watching?{' '} + Moving along… I guess if you want children beaten, you have to do it yourself. + It's okay, Bender. I like cooking too. +

+

Oh, I think we should just stay friends.

+

+ No argument here. And when we woke up, we had these bodies. You guys go on without me! I'm going to go… + look for more stuff to steal! Oh, how awful. Did he at least die painlessly? …To shreds, you say. Well, how is + his wife holding up? …To shreds, you say. +

+
    +
  1. No! The kind with looting and maybe starting a few fires!
  2. +
  3. You are the last hope of the universe.
  4. +
  5. Hey, guess what you're accessories to.
  6. +
+
+ ); + } +} From beff2c01a2bd48911fd7026b94d3c0a7725df5ba Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Tue, 14 May 2024 13:14:30 +0500 Subject: [PATCH 040/197] chore: fix MaskedInput test --- .../idle, focus, edit, blur/chrome/blured.png | 0 .../idle, focus, edit, blur/chrome/edited.png | 0 .../chrome/focused.png | 0 .../idle, focus, edit, blur/chrome/idle.png | 0 .../firefox/blured.png | 0 .../firefox/edited.png | 0 .../firefox/focused.png | 0 .../idle, focus, edit, blur/firefox/idle.png | 0 .../idle, focus, blur/chrome/blured.png | 0 .../idle, focus, blur/chrome/focused.png | 0 .../idle, focus, blur/chrome/idle.png | 0 .../idle, focus, blur/firefox/blured.png | 0 .../idle, focus, blur/firefox/focused.png | 0 .../idle, focus, blur/firefox/idle.png | 0 .../idle, focus, blur/chrome/blured.png | 0 .../idle, focus, blur/chrome/focused.png | 0 .../idle, focus, blur/chrome/idle.png | 0 .../idle, focus, blur/firefox/blured.png | 0 .../idle, focus, blur/firefox/focused.png | 0 .../idle, focus, blur/firefox/idle.png | 0 .../images/MaskedInput/Mask/firefox2022.png | 4 +- .../MaskedInput/Mask/firefox2022Dark.png | 4 +- .../images/MaskedInput/Mask/firefox8px.png | 4 +- .../idle, shift, rewrite/chrome/idle.png | 0 .../idle, shift, rewrite/chrome/rewrite.png | 0 .../idle, shift, rewrite/chrome/shift.png | 0 .../idle, shift, rewrite/firefox/idle.png | 0 .../idle, shift, rewrite/firefox/rewrite.png | 0 .../idle, shift, rewrite/firefox/shift.png | 0 .../Plain focused/chrome/focused.png | 0 .../Plain focused/chrome/plain.png | 0 .../Plain focused/firefox/focused.png | 0 .../Plain focused/firefox/plain.png | 0 .../Plain, selected/chrome/plain.png | 0 .../Plain, selected/chrome/selected.png | 0 .../Plain, selected/firefox/plain.png | 0 .../Plain, selected/firefox/selected.png | 0 .../Selected/chrome/Selected.png | 0 .../Selected/firefox/Selected.png | 0 .../PlainAndTyped/chrome/plain.png | 0 .../PlainAndTyped/chrome/typed.png | 0 .../PlainAndTyped/firefox/plain.png | 0 .../PlainAndTyped/firefox/typed.png | 0 .../idle, focus, edit, blur/chrome/blured.png | 0 .../idle, focus, edit, blur/chrome/edited.png | 0 .../chrome/focused.png | 0 .../idle, focus, edit, blur/chrome/idle.png | 0 .../firefox/blured.png | 0 .../firefox/edited.png | 0 .../firefox/focused.png | 0 .../idle, focus, edit, blur/firefox/idle.png | 0 .../__creevey__/MaskedInput.creevey.ts | 152 ++++++++++++++ .../__stories__/MaskedInput.stories.tsx | 192 ++++++++++++++++++ 53 files changed, 350 insertions(+), 6 deletions(-) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Default/idle, focus, edit, blur/chrome/blured.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Default/idle, focus, edit, blur/chrome/edited.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Default/idle, focus, edit, blur/chrome/focused.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Default/idle, focus, edit, blur/chrome/idle.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Default/idle, focus, edit, blur/firefox/blured.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Default/idle, focus, edit, blur/firefox/edited.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Default/idle, focus, edit, blur/firefox/focused.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Default/idle, focus, edit, blur/firefox/idle.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Idle Focus Blur With Prefix/idle, focus, blur/chrome/blured.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Idle Focus Blur With Prefix/idle, focus, blur/chrome/focused.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Idle Focus Blur With Prefix/idle, focus, blur/chrome/idle.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Idle Focus Blur With Prefix/idle, focus, blur/firefox/blured.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Idle Focus Blur With Prefix/idle, focus, blur/firefox/focused.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Idle Focus Blur With Prefix/idle, focus, blur/firefox/idle.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Idle Focus Blur/idle, focus, blur/chrome/blured.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Idle Focus Blur/idle, focus, blur/chrome/focused.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Idle Focus Blur/idle, focus, blur/chrome/idle.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Idle Focus Blur/idle, focus, blur/firefox/blured.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Idle Focus Blur/idle, focus, blur/firefox/focused.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Idle Focus Blur/idle, focus, blur/firefox/idle.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Rewrite In Middle/idle, shift, rewrite/chrome/idle.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Rewrite In Middle/idle, shift, rewrite/chrome/rewrite.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Rewrite In Middle/idle, shift, rewrite/chrome/shift.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Rewrite In Middle/idle, shift, rewrite/firefox/idle.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Rewrite In Middle/idle, shift, rewrite/firefox/rewrite.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Rewrite In Middle/idle, shift, rewrite/firefox/shift.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Select All By Prop/Plain focused/chrome/focused.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Select All By Prop/Plain focused/chrome/plain.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Select All By Prop/Plain focused/firefox/focused.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Select All By Prop/Plain focused/firefox/plain.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Select all by button/Plain, selected/chrome/plain.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Select all by button/Plain, selected/chrome/selected.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Select all by button/Plain, selected/firefox/plain.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Select all by button/Plain, selected/firefox/selected.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Select all by button/Selected/chrome/Selected.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Select all by button/Selected/firefox/Selected.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/plain.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/typed.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/plain.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/typed.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/With Custom Unmasked Value/idle, focus, edit, blur/chrome/blured.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/With Custom Unmasked Value/idle, focus, edit, blur/chrome/edited.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/With Custom Unmasked Value/idle, focus, edit, blur/chrome/focused.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/With Custom Unmasked Value/idle, focus, edit, blur/chrome/idle.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/With Custom Unmasked Value/idle, focus, edit, blur/firefox/blured.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/With Custom Unmasked Value/idle, focus, edit, blur/firefox/edited.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/With Custom Unmasked Value/idle, focus, edit, blur/firefox/focused.png (100%) rename packages/react-ui/.creevey/images/MaskedInput/{Functional tests => }/With Custom Unmasked Value/idle, focus, edit, blur/firefox/idle.png (100%) create mode 100644 packages/react-ui/components/MaskedInput/__creevey__/MaskedInput.creevey.ts create mode 100644 packages/react-ui/components/MaskedInput/__stories__/MaskedInput.stories.tsx diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Default/idle, focus, edit, blur/chrome/blured.png b/packages/react-ui/.creevey/images/MaskedInput/Default/idle, focus, edit, blur/chrome/blured.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Default/idle, focus, edit, blur/chrome/blured.png rename to packages/react-ui/.creevey/images/MaskedInput/Default/idle, focus, edit, blur/chrome/blured.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Default/idle, focus, edit, blur/chrome/edited.png b/packages/react-ui/.creevey/images/MaskedInput/Default/idle, focus, edit, blur/chrome/edited.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Default/idle, focus, edit, blur/chrome/edited.png rename to packages/react-ui/.creevey/images/MaskedInput/Default/idle, focus, edit, blur/chrome/edited.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Default/idle, focus, edit, blur/chrome/focused.png b/packages/react-ui/.creevey/images/MaskedInput/Default/idle, focus, edit, blur/chrome/focused.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Default/idle, focus, edit, blur/chrome/focused.png rename to packages/react-ui/.creevey/images/MaskedInput/Default/idle, focus, edit, blur/chrome/focused.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Default/idle, focus, edit, blur/chrome/idle.png b/packages/react-ui/.creevey/images/MaskedInput/Default/idle, focus, edit, blur/chrome/idle.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Default/idle, focus, edit, blur/chrome/idle.png rename to packages/react-ui/.creevey/images/MaskedInput/Default/idle, focus, edit, blur/chrome/idle.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Default/idle, focus, edit, blur/firefox/blured.png b/packages/react-ui/.creevey/images/MaskedInput/Default/idle, focus, edit, blur/firefox/blured.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Default/idle, focus, edit, blur/firefox/blured.png rename to packages/react-ui/.creevey/images/MaskedInput/Default/idle, focus, edit, blur/firefox/blured.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Default/idle, focus, edit, blur/firefox/edited.png b/packages/react-ui/.creevey/images/MaskedInput/Default/idle, focus, edit, blur/firefox/edited.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Default/idle, focus, edit, blur/firefox/edited.png rename to packages/react-ui/.creevey/images/MaskedInput/Default/idle, focus, edit, blur/firefox/edited.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Default/idle, focus, edit, blur/firefox/focused.png b/packages/react-ui/.creevey/images/MaskedInput/Default/idle, focus, edit, blur/firefox/focused.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Default/idle, focus, edit, blur/firefox/focused.png rename to packages/react-ui/.creevey/images/MaskedInput/Default/idle, focus, edit, blur/firefox/focused.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Default/idle, focus, edit, blur/firefox/idle.png b/packages/react-ui/.creevey/images/MaskedInput/Default/idle, focus, edit, blur/firefox/idle.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Default/idle, focus, edit, blur/firefox/idle.png rename to packages/react-ui/.creevey/images/MaskedInput/Default/idle, focus, edit, blur/firefox/idle.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur With Prefix/idle, focus, blur/chrome/blured.png b/packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur With Prefix/idle, focus, blur/chrome/blured.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur With Prefix/idle, focus, blur/chrome/blured.png rename to packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur With Prefix/idle, focus, blur/chrome/blured.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur With Prefix/idle, focus, blur/chrome/focused.png b/packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur With Prefix/idle, focus, blur/chrome/focused.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur With Prefix/idle, focus, blur/chrome/focused.png rename to packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur With Prefix/idle, focus, blur/chrome/focused.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur With Prefix/idle, focus, blur/chrome/idle.png b/packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur With Prefix/idle, focus, blur/chrome/idle.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur With Prefix/idle, focus, blur/chrome/idle.png rename to packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur With Prefix/idle, focus, blur/chrome/idle.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur With Prefix/idle, focus, blur/firefox/blured.png b/packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur With Prefix/idle, focus, blur/firefox/blured.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur With Prefix/idle, focus, blur/firefox/blured.png rename to packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur With Prefix/idle, focus, blur/firefox/blured.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur With Prefix/idle, focus, blur/firefox/focused.png b/packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur With Prefix/idle, focus, blur/firefox/focused.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur With Prefix/idle, focus, blur/firefox/focused.png rename to packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur With Prefix/idle, focus, blur/firefox/focused.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur With Prefix/idle, focus, blur/firefox/idle.png b/packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur With Prefix/idle, focus, blur/firefox/idle.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur With Prefix/idle, focus, blur/firefox/idle.png rename to packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur With Prefix/idle, focus, blur/firefox/idle.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur/idle, focus, blur/chrome/blured.png b/packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur/idle, focus, blur/chrome/blured.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur/idle, focus, blur/chrome/blured.png rename to packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur/idle, focus, blur/chrome/blured.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur/idle, focus, blur/chrome/focused.png b/packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur/idle, focus, blur/chrome/focused.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur/idle, focus, blur/chrome/focused.png rename to packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur/idle, focus, blur/chrome/focused.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur/idle, focus, blur/chrome/idle.png b/packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur/idle, focus, blur/chrome/idle.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur/idle, focus, blur/chrome/idle.png rename to packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur/idle, focus, blur/chrome/idle.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur/idle, focus, blur/firefox/blured.png b/packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur/idle, focus, blur/firefox/blured.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur/idle, focus, blur/firefox/blured.png rename to packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur/idle, focus, blur/firefox/blured.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur/idle, focus, blur/firefox/focused.png b/packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur/idle, focus, blur/firefox/focused.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur/idle, focus, blur/firefox/focused.png rename to packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur/idle, focus, blur/firefox/focused.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur/idle, focus, blur/firefox/idle.png b/packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur/idle, focus, blur/firefox/idle.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Idle Focus Blur/idle, focus, blur/firefox/idle.png rename to packages/react-ui/.creevey/images/MaskedInput/Idle Focus Blur/idle, focus, blur/firefox/idle.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Mask/firefox2022.png b/packages/react-ui/.creevey/images/MaskedInput/Mask/firefox2022.png index 8ad95efaf1c..52fdbdc1d9f 100644 --- a/packages/react-ui/.creevey/images/MaskedInput/Mask/firefox2022.png +++ b/packages/react-ui/.creevey/images/MaskedInput/Mask/firefox2022.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:221dc157e260f443d1c51dfdcd2202ce6e49329a1955c158c2c9c348fcde8a6d -size 161917 +oid sha256:4f69403702cbfeff2db5409e7c64f339153b8924d430902afe7fa7d3f52c4df4 +size 161926 diff --git a/packages/react-ui/.creevey/images/MaskedInput/Mask/firefox2022Dark.png b/packages/react-ui/.creevey/images/MaskedInput/Mask/firefox2022Dark.png index be4fff34147..12044ff8b46 100644 --- a/packages/react-ui/.creevey/images/MaskedInput/Mask/firefox2022Dark.png +++ b/packages/react-ui/.creevey/images/MaskedInput/Mask/firefox2022Dark.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:83e78219b25e983a77e6b5ab1338e4df2c7a7a615b5a932fba296308a31a5ed1 -size 159480 +oid sha256:0aa7101418977798f56e32f924b2a9e361c0433763290f6dd719b8290748f31e +size 159488 diff --git a/packages/react-ui/.creevey/images/MaskedInput/Mask/firefox8px.png b/packages/react-ui/.creevey/images/MaskedInput/Mask/firefox8px.png index 00ee0d3f2b5..c0f0d7321e0 100644 --- a/packages/react-ui/.creevey/images/MaskedInput/Mask/firefox8px.png +++ b/packages/react-ui/.creevey/images/MaskedInput/Mask/firefox8px.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e76df3f6db71e8b3b64c75d04d3475ee21e75c09440e17e1f23b1b54514d46b -size 159488 +oid sha256:dcc46f7c4356e6a703dfe50b99e0ed739d1857558e1a1ed99461b771fda83955 +size 159484 diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Rewrite In Middle/idle, shift, rewrite/chrome/idle.png b/packages/react-ui/.creevey/images/MaskedInput/Rewrite In Middle/idle, shift, rewrite/chrome/idle.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Rewrite In Middle/idle, shift, rewrite/chrome/idle.png rename to packages/react-ui/.creevey/images/MaskedInput/Rewrite In Middle/idle, shift, rewrite/chrome/idle.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Rewrite In Middle/idle, shift, rewrite/chrome/rewrite.png b/packages/react-ui/.creevey/images/MaskedInput/Rewrite In Middle/idle, shift, rewrite/chrome/rewrite.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Rewrite In Middle/idle, shift, rewrite/chrome/rewrite.png rename to packages/react-ui/.creevey/images/MaskedInput/Rewrite In Middle/idle, shift, rewrite/chrome/rewrite.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Rewrite In Middle/idle, shift, rewrite/chrome/shift.png b/packages/react-ui/.creevey/images/MaskedInput/Rewrite In Middle/idle, shift, rewrite/chrome/shift.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Rewrite In Middle/idle, shift, rewrite/chrome/shift.png rename to packages/react-ui/.creevey/images/MaskedInput/Rewrite In Middle/idle, shift, rewrite/chrome/shift.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Rewrite In Middle/idle, shift, rewrite/firefox/idle.png b/packages/react-ui/.creevey/images/MaskedInput/Rewrite In Middle/idle, shift, rewrite/firefox/idle.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Rewrite In Middle/idle, shift, rewrite/firefox/idle.png rename to packages/react-ui/.creevey/images/MaskedInput/Rewrite In Middle/idle, shift, rewrite/firefox/idle.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Rewrite In Middle/idle, shift, rewrite/firefox/rewrite.png b/packages/react-ui/.creevey/images/MaskedInput/Rewrite In Middle/idle, shift, rewrite/firefox/rewrite.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Rewrite In Middle/idle, shift, rewrite/firefox/rewrite.png rename to packages/react-ui/.creevey/images/MaskedInput/Rewrite In Middle/idle, shift, rewrite/firefox/rewrite.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Rewrite In Middle/idle, shift, rewrite/firefox/shift.png b/packages/react-ui/.creevey/images/MaskedInput/Rewrite In Middle/idle, shift, rewrite/firefox/shift.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Rewrite In Middle/idle, shift, rewrite/firefox/shift.png rename to packages/react-ui/.creevey/images/MaskedInput/Rewrite In Middle/idle, shift, rewrite/firefox/shift.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select All By Prop/Plain focused/chrome/focused.png b/packages/react-ui/.creevey/images/MaskedInput/Select All By Prop/Plain focused/chrome/focused.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select All By Prop/Plain focused/chrome/focused.png rename to packages/react-ui/.creevey/images/MaskedInput/Select All By Prop/Plain focused/chrome/focused.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select All By Prop/Plain focused/chrome/plain.png b/packages/react-ui/.creevey/images/MaskedInput/Select All By Prop/Plain focused/chrome/plain.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select All By Prop/Plain focused/chrome/plain.png rename to packages/react-ui/.creevey/images/MaskedInput/Select All By Prop/Plain focused/chrome/plain.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select All By Prop/Plain focused/firefox/focused.png b/packages/react-ui/.creevey/images/MaskedInput/Select All By Prop/Plain focused/firefox/focused.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select All By Prop/Plain focused/firefox/focused.png rename to packages/react-ui/.creevey/images/MaskedInput/Select All By Prop/Plain focused/firefox/focused.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select All By Prop/Plain focused/firefox/plain.png b/packages/react-ui/.creevey/images/MaskedInput/Select All By Prop/Plain focused/firefox/plain.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select All By Prop/Plain focused/firefox/plain.png rename to packages/react-ui/.creevey/images/MaskedInput/Select All By Prop/Plain focused/firefox/plain.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select all by button/Plain, selected/chrome/plain.png b/packages/react-ui/.creevey/images/MaskedInput/Select all by button/Plain, selected/chrome/plain.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select all by button/Plain, selected/chrome/plain.png rename to packages/react-ui/.creevey/images/MaskedInput/Select all by button/Plain, selected/chrome/plain.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select all by button/Plain, selected/chrome/selected.png b/packages/react-ui/.creevey/images/MaskedInput/Select all by button/Plain, selected/chrome/selected.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select all by button/Plain, selected/chrome/selected.png rename to packages/react-ui/.creevey/images/MaskedInput/Select all by button/Plain, selected/chrome/selected.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select all by button/Plain, selected/firefox/plain.png b/packages/react-ui/.creevey/images/MaskedInput/Select all by button/Plain, selected/firefox/plain.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select all by button/Plain, selected/firefox/plain.png rename to packages/react-ui/.creevey/images/MaskedInput/Select all by button/Plain, selected/firefox/plain.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select all by button/Plain, selected/firefox/selected.png b/packages/react-ui/.creevey/images/MaskedInput/Select all by button/Plain, selected/firefox/selected.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select all by button/Plain, selected/firefox/selected.png rename to packages/react-ui/.creevey/images/MaskedInput/Select all by button/Plain, selected/firefox/selected.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select all by button/Selected/chrome/Selected.png b/packages/react-ui/.creevey/images/MaskedInput/Select all by button/Selected/chrome/Selected.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select all by button/Selected/chrome/Selected.png rename to packages/react-ui/.creevey/images/MaskedInput/Select all by button/Selected/chrome/Selected.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select all by button/Selected/firefox/Selected.png b/packages/react-ui/.creevey/images/MaskedInput/Select all by button/Selected/firefox/Selected.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Select all by button/Selected/firefox/Selected.png rename to packages/react-ui/.creevey/images/MaskedInput/Select all by button/Selected/firefox/Selected.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/plain.png b/packages/react-ui/.creevey/images/MaskedInput/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/plain.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/plain.png rename to packages/react-ui/.creevey/images/MaskedInput/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/plain.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/typed.png b/packages/react-ui/.creevey/images/MaskedInput/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/typed.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/typed.png rename to packages/react-ui/.creevey/images/MaskedInput/Uncontrolled Input with Placeholder/PlainAndTyped/chrome/typed.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/plain.png b/packages/react-ui/.creevey/images/MaskedInput/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/plain.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/plain.png rename to packages/react-ui/.creevey/images/MaskedInput/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/plain.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/typed.png b/packages/react-ui/.creevey/images/MaskedInput/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/typed.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/typed.png rename to packages/react-ui/.creevey/images/MaskedInput/Uncontrolled Input with Placeholder/PlainAndTyped/firefox/typed.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/With Custom Unmasked Value/idle, focus, edit, blur/chrome/blured.png b/packages/react-ui/.creevey/images/MaskedInput/With Custom Unmasked Value/idle, focus, edit, blur/chrome/blured.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/With Custom Unmasked Value/idle, focus, edit, blur/chrome/blured.png rename to packages/react-ui/.creevey/images/MaskedInput/With Custom Unmasked Value/idle, focus, edit, blur/chrome/blured.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/With Custom Unmasked Value/idle, focus, edit, blur/chrome/edited.png b/packages/react-ui/.creevey/images/MaskedInput/With Custom Unmasked Value/idle, focus, edit, blur/chrome/edited.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/With Custom Unmasked Value/idle, focus, edit, blur/chrome/edited.png rename to packages/react-ui/.creevey/images/MaskedInput/With Custom Unmasked Value/idle, focus, edit, blur/chrome/edited.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/With Custom Unmasked Value/idle, focus, edit, blur/chrome/focused.png b/packages/react-ui/.creevey/images/MaskedInput/With Custom Unmasked Value/idle, focus, edit, blur/chrome/focused.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/With Custom Unmasked Value/idle, focus, edit, blur/chrome/focused.png rename to packages/react-ui/.creevey/images/MaskedInput/With Custom Unmasked Value/idle, focus, edit, blur/chrome/focused.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/With Custom Unmasked Value/idle, focus, edit, blur/chrome/idle.png b/packages/react-ui/.creevey/images/MaskedInput/With Custom Unmasked Value/idle, focus, edit, blur/chrome/idle.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/With Custom Unmasked Value/idle, focus, edit, blur/chrome/idle.png rename to packages/react-ui/.creevey/images/MaskedInput/With Custom Unmasked Value/idle, focus, edit, blur/chrome/idle.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/With Custom Unmasked Value/idle, focus, edit, blur/firefox/blured.png b/packages/react-ui/.creevey/images/MaskedInput/With Custom Unmasked Value/idle, focus, edit, blur/firefox/blured.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/With Custom Unmasked Value/idle, focus, edit, blur/firefox/blured.png rename to packages/react-ui/.creevey/images/MaskedInput/With Custom Unmasked Value/idle, focus, edit, blur/firefox/blured.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/With Custom Unmasked Value/idle, focus, edit, blur/firefox/edited.png b/packages/react-ui/.creevey/images/MaskedInput/With Custom Unmasked Value/idle, focus, edit, blur/firefox/edited.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/With Custom Unmasked Value/idle, focus, edit, blur/firefox/edited.png rename to packages/react-ui/.creevey/images/MaskedInput/With Custom Unmasked Value/idle, focus, edit, blur/firefox/edited.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/With Custom Unmasked Value/idle, focus, edit, blur/firefox/focused.png b/packages/react-ui/.creevey/images/MaskedInput/With Custom Unmasked Value/idle, focus, edit, blur/firefox/focused.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/With Custom Unmasked Value/idle, focus, edit, blur/firefox/focused.png rename to packages/react-ui/.creevey/images/MaskedInput/With Custom Unmasked Value/idle, focus, edit, blur/firefox/focused.png diff --git a/packages/react-ui/.creevey/images/MaskedInput/Functional tests/With Custom Unmasked Value/idle, focus, edit, blur/firefox/idle.png b/packages/react-ui/.creevey/images/MaskedInput/With Custom Unmasked Value/idle, focus, edit, blur/firefox/idle.png similarity index 100% rename from packages/react-ui/.creevey/images/MaskedInput/Functional tests/With Custom Unmasked Value/idle, focus, edit, blur/firefox/idle.png rename to packages/react-ui/.creevey/images/MaskedInput/With Custom Unmasked Value/idle, focus, edit, blur/firefox/idle.png diff --git a/packages/react-ui/components/MaskedInput/__creevey__/MaskedInput.creevey.ts b/packages/react-ui/components/MaskedInput/__creevey__/MaskedInput.creevey.ts new file mode 100644 index 00000000000..6503c2d3485 --- /dev/null +++ b/packages/react-ui/components/MaskedInput/__creevey__/MaskedInput.creevey.ts @@ -0,0 +1,152 @@ +import { story, kind, test } from 'creevey'; + +const testMaskedInput = () => { + test('idle, focus, edit, blur', async function () { + const click = (css: string) => { + return this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css })); + }; + const idle = await this.takeScreenshot(); + await click('input').pause(500).perform(); + const focused = await this.takeScreenshot(); + await click('input').sendKeys('953').perform(); + const edited = await this.takeScreenshot(); + await click('body').perform(); + const blured = await this.takeScreenshot(); + await this.expect({ idle, focused, edited, blured }).to.matchImages(); + }); +}; + +const testIdleFocusBlur = () => { + test('idle, focus, blur', async function () { + const click = (css: string) => { + return this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css })); + }; + const idle = await this.takeScreenshot(); + await click('input').pause(500).perform(); + const focused = await this.takeScreenshot(); + await click('body').perform(); + const blured = await this.takeScreenshot(); + await this.expect({ idle, focused, blured }).to.matchImages(); + }); +}; + +const testRewriteInMiddle = () => { + test('idle, shift, rewrite', async function () { + const idle = await this.takeScreenshot(); + const input = await this.browser.findElement({ css: 'input' }); + this.browser + .actions({ bridge: true }) + .click(input) + .keyDown(this.keys.ARROW_LEFT) + .keyDown(this.keys.ARROW_LEFT) + .sendKeys('12') + .perform(); + const shift = await this.takeScreenshot(); + this.browser + .actions({ bridge: true }) + .click(input) + .keyDown(this.keys.ARROW_LEFT) + .keyDown(this.keys.ARROW_LEFT) + .sendKeys('56') + .perform(); + const rewrite = await this.takeScreenshot(); + await this.expect({ idle, shift, rewrite }).to.matchImages(); + }); +}; + +kind('MaskedInput', () => { + story('Default', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + testMaskedInput(); + }); + + story('IdleFocusBlur', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + testIdleFocusBlur(); + }); + + story('IdleFocusBlurWithPrefix', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + testIdleFocusBlur(); + }); + + story('WithCustomUnmaskedValue', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + testMaskedInput(); + }); + + story('SelectAllByProp', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + test('Plain focused', async function () { + const plain = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'label' })) + .perform(); + const focused = await this.takeScreenshot(); + await this.expect({ plain, focused }).to.matchImages(); + }); + }); + + story('SelectAllByButton', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + test('Plain, selected', async function () { + const plain = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="select-all"]' })) + .perform(); + const selected = await this.takeScreenshot(); + await this.expect({ plain, selected }).to.matchImages(); + }); + }); + + story('UncontrolledInputWithPlaceholder', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + test('PlainAndTyped', async function () { + const plain = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'input' })) + .sendKeys('text') + .perform(); + const typed = await this.takeScreenshot(); + await this.expect({ plain, typed }).to.matchImages(); + }); + }); + + story('RewriteInMiddle', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + testRewriteInMiddle(); + }); +}); diff --git a/packages/react-ui/components/MaskedInput/__stories__/MaskedInput.stories.tsx b/packages/react-ui/components/MaskedInput/__stories__/MaskedInput.stories.tsx new file mode 100644 index 00000000000..5aee3aa6790 --- /dev/null +++ b/packages/react-ui/components/MaskedInput/__stories__/MaskedInput.stories.tsx @@ -0,0 +1,192 @@ +// TODO: Rewrite stories and enable rule (in process of functional refactoring). +/* eslint-disable react/no-unstable-nested-components */ +import React, { useState } from 'react'; +import SearchIcon from '@skbkontur/react-icons/Search'; + +import { ComponentTable } from '../../../internal/ComponentTable'; +import { Meta, Story } from '../../../typings/stories'; +import { MaskedInput, MaskedInputProps } from '../MaskedInput'; +import { Input } from '../../Input'; + +export default { + title: 'MaskedInput', +} as Meta; + +type InputState = Partial; + +const sizeStates: InputState[] = [{ size: 'small' }, { size: 'medium' }, { size: 'large' }]; + +export const Mask: Story = () => ( + ({ props: x }))} + rows={maskStates.map((x) => ({ props: x }))} + presetProps={{ mask: '(999) 999-99-99' }} + /> +); + +const maskStates: InputState[] = [ + {}, + { defaultValue: '95678901' }, + { defaultValue: '956789010A' }, + { mask: '****', value: 'overflow' }, + { placeholder: 'mask with placeholder' }, + { alwaysShowMask: true }, + { alwaysShowMask: true, maskChar: null }, + { alwaysShowMask: true, maskChar: 'X' }, + { alwaysShowMask: true, defaultValue: '95678901' }, + { alwaysShowMask: true, defaultValue: '956789010A' }, + { alwaysShowMask: true, placeholder: 'mask with placeholder' }, + { alwaysShowMask: true, type: 'email', mask: '*** ***', defaultValue: 'Value' }, + { alwaysShowMask: true, type: 'tel', mask: '*** ***', defaultValue: 'Value' }, + { alwaysShowMask: true, type: 'url', mask: '*** ***', defaultValue: 'Value' }, + { alwaysShowMask: true, type: 'search', mask: '*** ***', defaultValue: 'Value' }, +]; + +export const PrefixOrSuffix: Story = () => ( + ({ props: x }))} + rows={inputPrefixOrSuffixStates.map((x) => ({ props: x }))} + presetProps={{ mask: '+7 (999) 999 99 99' }} + /> +); +const inputPrefixOrSuffixStates: InputState[] = [ + {}, + { rightIcon: }, + { rightIcon: , value: '+79876543210' }, + { leftIcon: }, + { leftIcon: , value: '+79876543210' }, + { rightIcon: , placeholder: 'Placeholder' }, + { leftIcon: , placeholder: 'Placeholder' }, + { prefix: 'prefix:' }, + { prefix: 'prefix:', value: '+79876543210' }, + { suffix: '/suffix' }, + { suffix: '/suffix', value: '+79876543210' }, +]; + +export const PrefixesAndSuffixes: Story = () => ( + ({ props: x }))} + presetProps={{ mask: '+7 (999) 999 99 99', width: '250px' }} + /> +); +const prefixesAndSuffixesStates: InputState[] = [ + { + rightIcon: , + leftIcon: , + prefix: 'prefix:', + suffix: '/suffix', + placeholder: 'Placeholder', + }, + { + rightIcon: , + leftIcon: , + prefix: 'prefix:', + suffix: '/suffix', + value: '+7987654321', + alwaysShowMask: true, + }, +]; + +export const Validations: Story = () => ( + ({ props: x }))} + rows={validationsStates.map((x) => ({ props: x }))} + presetProps={{ mask: '99:99' }} + /> +); + +const validationsStates: InputState[] = [ + {}, + { borderless: true }, + { disabled: true }, + { alwaysShowMask: true, disabled: true }, + { warning: true }, + { error: true }, +]; + +export const Positions: Story = () => ( + ({ props: x }))} + rows={positionsStates.map((x) => ({ props: x }))} + presetProps={{ alwaysShowMask: true, mask: '**** **** ****' }} + /> +); + +const positionsStates: InputState[] = [ + { value: '1' }, + { value: '1111 1' }, + { value: '1111 1111 111' }, + { value: 'W' }, + { value: 'WWWW W' }, + { value: 'WWWW WWWW WWW' }, + { value: 'W1W1 W1W1 W1' }, +]; + +export const Default: Story = () => ( + +); + +export const IdleFocusBlur: Story = () => ( + +); + +export const IdleFocusBlurWithPrefix: Story = () => ( + +); + +export const WithCustomUnmaskedValue: Story = () => { + const [value, setValue] = useState('+795'); + + return ( + setValue(value.replace(/\s/g, ''))} + /> + ); +}; + +export const SelectAllByProp: Story = () => ( + +); + +export const SelectAllByButton: Story = () => { + let input: Input | null = null; + + const selectAll = () => { + if (input) { + input.selectAll(); + } + }; + + return ( +
+
+ (input = element)} mask={'99:99'} defaultValue="12:34" /> +
+ +
+ ); +}; +SelectAllByButton.storyName = 'Select all by button'; + +export const UncontrolledInputWithPlaceholder: Story = () => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [_value, setValue] = React.useState(); + return setValue(value)} />; +}; +UncontrolledInputWithPlaceholder.storyName = 'Uncontrolled Input with Placeholder'; + +export const RewriteInMiddle: Story = () => ; From 8c59154c5a4d821ef3fd45d3095532837ff65351 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Tue, 14 May 2024 13:18:11 +0500 Subject: [PATCH 041/197] chore: fix MenuFooter test --- .../__stories__/MenuFooter.stories.tsx | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 packages/react-ui/components/MenuFooter/__stories__/MenuFooter.stories.tsx diff --git a/packages/react-ui/components/MenuFooter/__stories__/MenuFooter.stories.tsx b/packages/react-ui/components/MenuFooter/__stories__/MenuFooter.stories.tsx new file mode 100644 index 00000000000..d4051634436 --- /dev/null +++ b/packages/react-ui/components/MenuFooter/__stories__/MenuFooter.stories.tsx @@ -0,0 +1,20 @@ +import React from 'react'; + +import { Meta } from '../../../typings/stories'; +import { MenuFooter } from '../MenuFooter'; +import { Gapped } from '../../Gapped'; + +export default { + title: 'MenuFooter', +} as Meta; + +export const Size = () => { + return ( + + Маленький + Средний + Большой + + ); +}; +Size.storyName = 'size'; From de4bf513fd7568dfe2f075b8189b4dce443025d2 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Tue, 14 May 2024 13:18:21 +0500 Subject: [PATCH 042/197] chore: fix MenuHeader test --- .../__stories__/MenuHeader.stories.tsx | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 packages/react-ui/components/MenuHeader/__stories__/MenuHeader.stories.tsx diff --git a/packages/react-ui/components/MenuHeader/__stories__/MenuHeader.stories.tsx b/packages/react-ui/components/MenuHeader/__stories__/MenuHeader.stories.tsx new file mode 100644 index 00000000000..50b2173db57 --- /dev/null +++ b/packages/react-ui/components/MenuHeader/__stories__/MenuHeader.stories.tsx @@ -0,0 +1,20 @@ +import React from 'react'; + +import { Meta } from '../../../typings/stories'; +import { MenuHeader } from '../MenuHeader'; +import { Gapped } from '../../Gapped'; + +export default { + title: 'MenuHeader', +} as Meta; + +export const Size = () => { + return ( + + Маленький + Средний + Большой + + ); +}; +Size.storyName = 'size'; From c2458ea53ac16912449846cdc7fc55b69b504a20 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Tue, 14 May 2024 13:18:30 +0500 Subject: [PATCH 043/197] chore: fix MenuItem test --- .../MenuItem/__stories__/MenuItem.stories.tsx | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 packages/react-ui/components/MenuItem/__stories__/MenuItem.stories.tsx diff --git a/packages/react-ui/components/MenuItem/__stories__/MenuItem.stories.tsx b/packages/react-ui/components/MenuItem/__stories__/MenuItem.stories.tsx new file mode 100644 index 00000000000..dacfb2c8de7 --- /dev/null +++ b/packages/react-ui/components/MenuItem/__stories__/MenuItem.stories.tsx @@ -0,0 +1,72 @@ +import React from 'react'; +import OkIcon from '@skbkontur/react-icons/Ok'; + +import { ThemeContext } from '../../../lib/theming/ThemeContext'; +import { ThemeFactory } from '../../../lib/theming/ThemeFactory'; +import { Meta } from '../../../typings/stories'; +import { MenuItem } from '../MenuItem'; +import { Gapped } from '../../Gapped'; + +export default { + title: 'MenuItem', +} as Meta; + +export const MobileMenuItemWithIcon = () => { + return ( + } isMobile> + Мобильный айтем с иконкой + + ); +}; +MobileMenuItemWithIcon.storyName = 'mobile menu item with icon'; + +export const MenuItemWithIcon = () => { + return }>Меню айтем с иконкой; +}; +MenuItemWithIcon.storyName = 'menu item with icon'; +MenuItemWithIcon.parameters = { + creevey: { + skip: { in: /^(?!\bchrome\b)/ }, + }, +}; + +export const MenuItemWithBiggerFontSize = () => { + return ( + + {(theme) => ( + + }>Меню айтем с увеличенным размером шрифта + + )} + + ); +}; +MenuItemWithBiggerFontSize.storyName = 'menu item with bigger font size'; +MenuItemWithBiggerFontSize.parameters = { + creevey: { + skip: { in: /^(?!\bchrome\b)/ }, + }, +}; + +export const Size = () => { + const comment = Комментарий; + return ( + + } comment={comment}> + Без размера + + } comment={comment}> + Маленький + + } comment={comment}> + Средний + + } comment={comment}> + Большой + + + ); +}; +Size.storyName = 'size'; From eb138e73b9399f085f656aa693784e09a8fc4f51 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Tue, 14 May 2024 13:21:04 +0500 Subject: [PATCH 044/197] chore: fix MiniModal test --- .../__stories__/MiniModal.stories.tsx | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 packages/react-ui/components/MiniModal/__stories__/MiniModal.stories.tsx diff --git a/packages/react-ui/components/MiniModal/__stories__/MiniModal.stories.tsx b/packages/react-ui/components/MiniModal/__stories__/MiniModal.stories.tsx new file mode 100644 index 00000000000..c940cfa981b --- /dev/null +++ b/packages/react-ui/components/MiniModal/__stories__/MiniModal.stories.tsx @@ -0,0 +1,138 @@ +import React from 'react'; +import { TrashCanIcon64Regular } from '@skbkontur/icons/TrashCanIcon64Regular'; +import { TechPhoneSmartIcon64Regular } from '@skbkontur/icons/TechPhoneSmartIcon64Regular'; + +import { MiniModal } from '../MiniModal'; +import { Button } from '../../Button'; +import { Modal } from '../../Modal'; +import { Meta, Story } from '../../../typings/stories'; +import { ThemeContext } from '../../../lib/theming/ThemeContext'; +import { THEME_2022 } from '../../../lib/theming/themes/Theme2022'; +import { ThemeFactory } from '../../../lib/theming/ThemeFactory'; + +export default { + title: 'MiniModal', + parameters: { creevey: { captureElement: '[data-tid="modal-content"]' } }, +} as Meta; + +export const Simple = () => ( + + Title + + + + +); + +export const MobileFullset: Story = () => ( + + {(theme) => ( + + + }>Title mobile + Lorem ipsum dolor sit amet, consectetur adipisicing elit. Earum, officia? + + + + + + + + + )} + +); +MobileFullset.parameters = { + viewport: { defaultViewport: 'iphone' }, + creevey: { captureElement: null }, +}; + +export const Description = () => ( + + Title + Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore, voluptatibus? + + + + +); + +export const TwoButtons = () => ( + + Title + + + + + +); + +export const Column = () => ( + + Title + + + + + +); + +export const ThreeButtons = () => ( + + Title + + + + + + +); + +export const Indent = () => ( + + Title + + + + + + + +); + +export const Icon = () => ( + + }>Title + + + + +); + +export const Custom = () => ( + + Delete? + + + + + +); From 058d57dbdb6bb8c3dda813a01a80b7e2c833ea16 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Tue, 14 May 2024 14:05:45 +0500 Subject: [PATCH 045/197] chore: fix Modal test --- .../Modal/__creevey__/Modal.creevey.ts | 264 +++++++ .../Modal/__stories__/Modal.stories.tsx | 659 ++++++++++++++++++ 2 files changed, 923 insertions(+) create mode 100644 packages/react-ui/components/Modal/__creevey__/Modal.creevey.ts create mode 100644 packages/react-ui/components/Modal/__stories__/Modal.stories.tsx diff --git a/packages/react-ui/components/Modal/__creevey__/Modal.creevey.ts b/packages/react-ui/components/Modal/__creevey__/Modal.creevey.ts new file mode 100644 index 00000000000..ca9e2a6533d --- /dev/null +++ b/packages/react-ui/components/Modal/__creevey__/Modal.creevey.ts @@ -0,0 +1,264 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +const topMiddleBottomModalTests = () => { + test('top', async function () { + await this.expect(await this.browser.takeScreenshot()).to.matchImage('top'); + }); + + test('middle', async function () { + await this.browser.executeScript(function () { + const modalContainer = window.document.querySelector('[data-tid="modal-container"]') as HTMLElement; + const modalContent = window.document.querySelector('[data-tid="modal-content"]') as HTMLElement; + + modalContainer.scrollTop = modalContent.offsetHeight / 2; + }); + await delay(100); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('middle'); + }); + + test('bottom', async function () { + await this.browser.executeScript(function () { + const modalContainer = window.document.querySelector('[data-tid="modal-container"]') as HTMLElement; + const modalContent = window.document.querySelector('[data-tid="modal-content"]') as HTMLElement; + + modalContainer.scrollTop = modalContent.offsetHeight; + }); + await delay(100); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('bottom'); + }); +}; + +kind('Modal', () => { + story('ModalWithFooterPanelStory', () => { + test('open modal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Button"]:nth-of-type(1)' })) + .perform(); + await delay(100); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); + }); + }); + + story('WithIconInput', () => { + test('open modal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); + }); + }); + + story('ModalOverAnotherModalStory', () => { + test('open first modal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-first-modal"]' })) + .perform(); + await delay(200); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open first modal'); + }); + + test('open second modal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-first-modal"]' })) + .perform(); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid~="open-second-modal"]' })) + .perform(); + await delay(100); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open second modal'); + }); + }); + + story('ModalWithoutFooterPanelStory', () => { + test('open modal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await delay(200); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); + }); + }); + + story('ModalWithoutFooterStory', () => { + test('open modal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); + }); + }); + + story('ModalMobileView', () => { + test('idle', async function () { + await this.expect(await this.browser.takeScreenshot()).to.matchImage('idle'); + }); + }); + + story('ModalWithVariableHeightOfContent', () => { + test('open modal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await delay(100); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); + }); + + test('toggle content height', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '#modal-inner [data-comp-name~="Toggle"]' })) + .pause(500) + .perform(); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('toggle content height'); + }); + }); + + story('ModalWithoutStickyElements', () => { + topMiddleBottomModalTests(); + }); + + story('SmallModalOnTheTop', () => { + test('open modal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await delay(100); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); + }); + + test('close by click on the cross', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid="modal-close"]' })) + .perform(); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('close by click on the cross'); + }); + + test("doesn't close by click on the content", async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid="modal-content-button"]' })) + .perform(); + await this.expect(await this.browser.takeScreenshot()).to.matchImage("doesn't close by click on the content"); + }); + + test('closes by click on the background', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid="modal-container"]' })) + .perform(); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('closes by click on the background'); + }); + }); + + story('ModalWithChildrenFromOtherComponent', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: ['top', 'middle'] }, + }, + }); + + topMiddleBottomModalTests(); + }); + + story('MobileModal', () => { + test('top', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await delay(200); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('top'); + }); + + test('middle', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await delay(200); + await this.browser.executeScript(function () { + const modalContent = window.document.querySelector('.focus-lock-container') as HTMLElement; + const modalBody = window.document.querySelector('[data-comp-name~="Modal.Body"] ') as HTMLElement; + + modalContent.scrollTop = modalBody.offsetHeight / 2; + }); + await delay(100); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('middle'); + }); + + test('bottom', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await delay(200); + await this.browser.executeScript(function () { + const modalContent = window.document.querySelector('.focus-lock-container') as HTMLElement; + const modalBody = window.document.querySelector('[data-comp-name~="Modal.Body"] ') as HTMLElement; + + modalContent.scrollTop = modalBody.offsetHeight; + }); + await delay(100); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('bottom'); + }); + }); +}); diff --git a/packages/react-ui/components/Modal/__stories__/Modal.stories.tsx b/packages/react-ui/components/Modal/__stories__/Modal.stories.tsx new file mode 100644 index 00000000000..88b3ba7715a --- /dev/null +++ b/packages/react-ui/components/Modal/__stories__/Modal.stories.tsx @@ -0,0 +1,659 @@ +// TODO: Rewrite stories and enable rule (in process of functional refactoring). +/* eslint-disable react/no-unstable-nested-components */ +import React, { useState, useContext } from 'react'; +import BorderAllIcon from '@skbkontur/react-icons/BorderAll'; + +import { ThemeFactory } from '../../../lib/theming/ThemeFactory'; +import { Story } from '../../../typings/stories'; +import { Modal } from '../Modal'; +import { Button } from '../../Button'; +import { Input } from '../../Input'; +import { Toggle } from '../../Toggle'; +import { ThemeContext } from '../../../lib/theming/ThemeContext'; +import { ResponsiveLayout } from '../../ResponsiveLayout'; + +const basicFontStyle = { + fontSize: '14px', + lineHeight: '20px', + margin: '0', +}; + +interface ModalWithScrollableContentState { + opened: boolean; + panel: boolean; +} +class ModalWithScrollableContent extends React.Component { + public state: ModalWithScrollableContentState = { + opened: false, + panel: false, + }; + + public render() { + return ( +
+ {this.state.opened && this.renderModal()} + +

+ On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized + by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble + that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, + which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to + distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able + to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances + and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to + be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle + of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse + pains. +

+

+ On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized + by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble + that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, + which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to + distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able + to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances + and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to + be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle + of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse + pains. +

+
+ ); + } + + public renderModal() { + return ( + + Title + +

Use rxjs operators with react hooks

+ +
+ this.setState(({ panel }: ModalWithScrollableContentState) => ({ panel: !panel }))} + />{' '} + Panel {this.state.panel ? 'enabled' : 'disabled'} +
+
+ + + +
+ ); + } + + public open = () => { + this.setState({ opened: true }); + }; + + public close = () => { + this.setState({ opened: false }); + }; +} + +interface ModalWithIconInputState { + opened: boolean; +} +class ModalWithIconInput extends React.Component { + public state: ModalWithIconInputState = { + opened: false, + }; + + public renderModal() { + return ( + + + } rightIcon={} /> + } rightIcon={} /> + } rightIcon={} /> + + + } rightIcon={} /> + } rightIcon={} /> + } rightIcon={} /> + + + } rightIcon={} /> + } rightIcon={} /> + } rightIcon={} /> + + + ); + } + + public render() { + return ( +
+ {this.state.opened && this.renderModal()} + +
+ ); + } + + public open = () => { + this.setState({ opened: true }); + }; + + public close = () => { + this.setState({ opened: false }); + }; +} + +class ModalOverAnotherModal extends React.Component { + public state = { + firstModalOpened: false, + secondModalOpened: false, + }; + + public renderModal(name: string, width: number) { + return ( + + Модалка #{name === 'firstModalOpened' ? '1' : '2'} + + {name === 'firstModalOpened' && ( + + )} + + + ); + } + + public render() { + const { firstModalOpened, secondModalOpened } = this.state; + + return ( +
+ {firstModalOpened && this.renderModal('firstModalOpened', 500)} + {secondModalOpened && this.renderModal('secondModalOpened', 300)} + +
+ ); + } + + public close(name: string) { + this.setState({ [name]: false }); + } +} + +const ModalWithFooterPanel = () => { + const [isOpen, setIsOpen] = useState(false); + + return ( +
+ {isOpen && ( + setIsOpen(false)}> + Адрес места осуществления предпринимательской деятельности + + + + + + + + + )} + +
+ ); +}; + +export const ModalWithFooterPanelStory: Story = () => ; +ModalWithFooterPanelStory.storyName = 'Modal with footer panel'; + +interface ModalWithoutFooterPanelState { + opened: boolean; +} +class ModalWithoutFooterPanel extends React.Component { + public state: ModalWithoutFooterPanelState = { + opened: false, + }; + + public renderModal() { + return ( + + Исправление ошибок + +

+ Исправить ошибки можно у нас в сервисе. Для этого загрузите документы для редактирования. Также можно + посмотреть ошибки, исправить их в учетной программе и импортировать заново. +

+
+ + + + +
+ ); + } + + public render() { + return ( +
+ {this.state.opened && this.renderModal()} + +
+ ); + } + + public open = () => { + this.setState({ opened: true }); + }; + + public close = () => { + this.setState({ opened: false }); + }; +} + +interface ModalWithoutFooterState { + opened: boolean; +} +class ModalWithoutFooter extends React.Component { + public state: ModalWithoutFooterState = { + opened: false, + }; + + public renderModal() { + return ( + + Воспользуйтесь другим браузером + +

+ Некоторые функции не работают в вашем браузере. Чтобы все работало, установите один из этих браузеров: + Firefox, Opera, Chrome. +

+
+
+ ); + } + + public render() { + return ( +
+ {this.state.opened && this.renderModal()} + +
+ ); + } + + public open = () => { + this.setState({ opened: true }); + }; + + public close = () => { + this.setState({ opened: false }); + }; +} + +interface ModalInnerState { + bigHeight: boolean; +} +class ModalInner extends React.Component { + public state: ModalInnerState = { + bigHeight: false, + }; + + public render() { + return ( + + ); + } +} + +interface ModalWithVariableHeightState { + opened: boolean; + panel: boolean; +} +class ModalWithVariableHeight extends React.Component { + public state: ModalWithVariableHeightState = { + opened: false, + panel: false, + }; + + public render() { + return ( +
+ {this.state.opened && ( + + Title + +

Use rxjs operators with react hooks

+ + {this.props.children} + +
+ this.setState(({ panel }: ModalWithVariableHeightState) => ({ panel: !panel }))} + />{' '} + Panel {this.state.panel ? 'enabled' : 'disabled'} +
+
+ + + +
+ )} + +
+ ); + } + + public open = () => { + this.setState({ opened: true }); + }; + + public close = () => { + this.setState({ opened: false }); + }; +} + +class SmallModalOnTop extends React.Component { + public state = { + opened: false, + }; + + public renderModal() { + return ( + + Modal + + + + + ); + } + + public render() { + return ( +
+ {this.state.opened && this.renderModal()} + +
+ ); + } + + public open = () => { + this.setState({ opened: true }); + }; + + public close = () => { + this.setState({ opened: false }); + }; +} + +export default { title: 'Modal' }; + +export const WithScrollableParentContent = () => ; +WithScrollableParentContent.storyName = 'With scrollable parent content'; +WithScrollableParentContent.parameters = { creevey: { skip: true } }; + +export const WithIconInput: Story = () => ; + +export const ModalOverAnotherModalStory: Story = () => ; +ModalOverAnotherModalStory.storyName = 'Modal over another modal'; + +export const DisabledModal = () => ( + + Disabled + Content of disabled body + +); +DisabledModal.storyName = 'Disabled modal'; +DisabledModal.parameters = { creevey: { skip: true } }; + +export const ModalWithoutFooterPanelStory: Story = () => ; +ModalWithoutFooterPanelStory.storyName = 'Modal without footer panel'; + +export const ModalWithoutFooterStory: Story = () => ; +ModalWithoutFooterStory.storyName = 'Modal without footer'; + +export const ModalWithoutHeader = () => ( + + +
+ Некоторые функции не работают в вашем браузере. Чтобы все работало, установите один из этих браузеров: Firefox, + divpera, Chrome. +
+
+
+); +ModalWithoutHeader.storyName = 'Modal without header'; +ModalWithoutHeader.parameters = { creevey: { captureElement: null } }; + +export const ModalMobileView: Story = () => { + const theme = useContext(ThemeContext); + + return ( + + + Воспользуйтесь другим браузером + + Некоторые функции не работают в вашем браузере. Чтобы все работало, установите один из этих браузеров: + Firefox, Opera, Chrome. + + + + + + + ); +}; +ModalMobileView.storyName = 'Modal mobile view'; +ModalMobileView.parameters = { + viewport: { defaultViewport: 'iphone' }, +}; + +export const ModalWithVariableHeightOfContent: Story = () => ( + + + +); +ModalWithVariableHeightOfContent.storyName = 'Modal with variable height of content'; + +export const ModalWithoutStickyElements: Story = () => ( + + Header + + {new Array(200).fill('Use rxjs operators with react hooks.').map((item, index) => ( +

{item}

+ ))} +
+ Footer +
+); +ModalWithoutStickyElements.storyName = 'Modal without sticky elements'; + +export const WithAlignTop = () => ( + + +

Use rxjs operators with react hooks.

+
+
+); +WithAlignTop.storyName = 'With alignTop'; +WithAlignTop.parameters = { creevey: { captureElement: null } }; + +export const SmallModalOnTheTop: Story = () => ; +SmallModalOnTheTop.storyName = 'Small modal on the Top'; + +export const ModalWithVeryLongHeaderWithoutSpaces = () => ( + + VeryLongAndStrangeHeaderWithoutMeaningAndSpaces + +); +ModalWithVeryLongHeaderWithoutSpaces.storyName = 'Modal with veryLongHeaderWithoutSpaces'; +ModalWithVeryLongHeaderWithoutSpaces.parameters = { creevey: { captureElement: null } }; + +export const ModalWithHeaderFromOtherComponent = () => { + const Header = () => Header ; + return ( + +
+ asdjhaklsdkajs +
+ ); +}; +ModalWithHeaderFromOtherComponent.storyName = 'Modal with Header from other Component'; +ModalWithHeaderFromOtherComponent.parameters = { creevey: { skip: true } }; + +export const ModalBodyWithoutPadding = () => ( + + {(theme) => { + return ( + + +
+

Loooooooong content content content

+

Loooooooong content content content

+

Loooooooong content content content

+

Loooooooong content content content

+
+
+
+ ); + }} +
+); +ModalBodyWithoutPadding.storyName = 'Modal with no-padding'; +ModalBodyWithoutPadding.parameters = { creevey: { captureElement: null } }; + +export const AlignCenterAndNoClose = () => ( + + +
Header
+
+ +
+

Loooooooong content content content

+
+
+
+); +AlignCenterAndNoClose.parameters = { creevey: { captureElement: null } }; + +const Header = () => Header; +const Body = () => ( + + {new Array(200).fill('Use rxjs operators with react hooks.').map((item, index) => ( +

{item}

+ ))} +
+); +const Footer = () => ( + + Footer + +); + +export const ModalWithChildrenFromOtherComponent = () => ( + +
+ +
+ +); + +export const MobileModal: Story = () => { + const [isOpen, setOpen] = useState(false); + const [showThirdButton, setShowThird] = useState(false); + + const modal = ( + + {({ isMobile }) => { + return ( + setOpen(false)}> + Это какой-то заголовок заголовок + +

+ {new Array(80).fill( + 'ст ст ст ст ст ст ст ст ст ст ст ст ст ст ст ст ст ст ст ст ст ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст тек ст', + 0, + 80, + )} +

+
+ + + + {showThirdButton && ( + + )} + +
+ ); + }} +
+ ); + + const render = ( +
+ + {isOpen && modal} +
+ ); + + return render; +}; +MobileModal.storyName = 'Mobile modal'; +MobileModal.parameters = { + viewport: { + defaultViewport: 'iphonePlus', + }, +}; From 4059d08d2d2d49ed8f118c2daca5a2e10b72317f Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Tue, 14 May 2024 14:12:52 +0500 Subject: [PATCH 046/197] chore: fix Paging test --- .../Paging/__creevey__/Paging.creevey.ts | 99 +++++++ .../Paging/__stories__/Paging.stories.tsx | 241 ++++++++++++++++++ 2 files changed, 340 insertions(+) create mode 100644 packages/react-ui/components/Paging/__creevey__/Paging.creevey.ts create mode 100644 packages/react-ui/components/Paging/__stories__/Paging.stories.tsx diff --git a/packages/react-ui/components/Paging/__creevey__/Paging.creevey.ts b/packages/react-ui/components/Paging/__creevey__/Paging.creevey.ts new file mode 100644 index 00000000000..b188d924830 --- /dev/null +++ b/packages/react-ui/components/Paging/__creevey__/Paging.creevey.ts @@ -0,0 +1,99 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('Paging', () => { + story('GoToAbsensePageStory', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'hover' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hover', 'Move to page by Ender'], + }, + flaky: { + in: ['firefox2022', 'firefox2022Dark'], + tests: ['Move focus right', 'Move to page by Ender'], + }, + }, + }); + + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('hover', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` }), + }) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('hover'); + }); + + test('change page by number', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('change page by number'); + }); + + test('change page by forwardLink', async function () { + // NOTE Firefox bug if click send right after click from previous test it results as double click + await delay(500); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: `[data-tid='Paging__forwardLink']` })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('change page by forwardLink'); + }); + + test('focused', async function () { + // NOTE Firefox bug if click send right after click from previous test it results as double click + await delay(500); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('focused'); + }); + + test('Move focus right', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` })) + .pause(100) + .sendKeys(this.keys.ARROW_RIGHT) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('Move focus right'); + }); + + test('Move to page by Ender', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` })) + .pause(100) + .sendKeys(this.keys.ARROW_RIGHT) + .pause(100) + .sendKeys(this.keys.ENTER) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('Move to page by Ender'); + }); + }); +}); diff --git a/packages/react-ui/components/Paging/__stories__/Paging.stories.tsx b/packages/react-ui/components/Paging/__stories__/Paging.stories.tsx new file mode 100644 index 00000000000..ca0a6ed64be --- /dev/null +++ b/packages/react-ui/components/Paging/__stories__/Paging.stories.tsx @@ -0,0 +1,241 @@ +import React from 'react'; +import { action } from '@storybook/addon-actions'; +import { ComponentStory } from '@storybook/react'; + +import { Meta, Story } from '../../../typings/stories'; +import { ItemComponentProps, Paging } from '../Paging'; +import { emptyHandler } from '../../../lib/utils'; +import { PagingProps } from '..'; + +const lorem = `Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolores +dignissimos labore expedita. Sapiente beatae eveniet sit, similique, +sunt corrupti deserunt ab eius nobis suscipit praesentium labore. +Distinctio hic asperiores consequatur?`; + +interface GoToAbsensePageState { + activePage: number; +} +class GoToAbsensePage extends React.Component { + public state: GoToAbsensePageState = { + activePage: 3, + }; + + public render() { + const pagesCount = this._getPagesCount(this.state.activePage); + return ( +
+
+ +
+
+ ); + } + + private _getPagesCount = (activePage: number) => { + return activePage <= 4 ? 7 : 5; + }; + + private _handlePageChange = (pageNumber: number) => { + const pagesCount = this._getPagesCount(pageNumber); + const activePage = Math.min(pageNumber, pagesCount); + this.setState({ activePage }); + }; +} + +interface PagingWithStateProps extends Partial { + pagesCount: number; +} +interface PagingWithStateState { + activePage: number; +} +class PagingWithState extends React.Component { + public state: PagingWithStateState = { + activePage: 1, + }; + + public render() { + return ( +
+ +
+ ); + } + + private _handlePageChange = (pageNumber: number) => { + this.setState({ activePage: pageNumber }, () => action('page cahnged')(this.state.activePage)); + }; +} + +const getPageFromHash = () => +document.location.hash.slice(1); + +const CustomComponent = ({ children, pageNumber, active, ...rest }: ItemComponentProps) => { + if (Paging.isForward(pageNumber)) { + return ( + + {children} + + ); + } + + return ( + + {children} + + ); +}; + +interface PagingWithCustomComponentProps { + pagesCount: number; +} +interface PagingWithCustomComponentState { + activePage: number; +} +class PagingWithCustomComponent extends React.Component { + public state: PagingWithCustomComponentState = { + activePage: 1, + }; + + public componentDidMount() { + document.location.hash = '#1'; + window.addEventListener('hashchange', this._handleHashChange); + } + + public componentWillUnmount() { + document.location.hash = ''; + window.removeEventListener('hashchange', this._handleHashChange); + } + + public render() { + return ( +
+ +
+ ); + } + + public _handlePageChange = (pageNumber: number) => { + document.location.hash = '#' + pageNumber; + }; + + public _handleHashChange = () => { + this.setState({ activePage: getPageFromHash() }); + }; +} + +export default { + title: 'Paging', + decorators: [ + (Story: () => JSX.Element) => ( +
+ +
+ ), + ], +} as Meta; + +export const GoToAbsensePageStory: Story = () => ; +GoToAbsensePageStory.storyName = 'GoToAbsensePage'; + +export const SimpleSamples = () => ( + <> + + + + + +); +SimpleSamples.storyName = 'SimpleSamples'; +SimpleSamples.parameters = { creevey: { skip: true } }; + +export const PagingWithCustomComponentStory = () => ; +PagingWithCustomComponentStory.storyName = 'PagingWithCustomComponent'; +PagingWithCustomComponentStory.parameters = { creevey: { skip: true } }; + +export const PagingWithGlobalListener = () => ; +PagingWithGlobalListener.storyName = 'Paging with global listener'; +PagingWithGlobalListener.parameters = { creevey: { skip: true } }; + +const Template: ComponentStory = (args) => { + return ; +}; + +export const WithLongItems = Template.bind({}); +WithLongItems.args = { + activePage: 753000, + pagesCount: 7530050, +}; + +export const DisabledPaging = () => { + return ; +}; +DisabledPaging.parameters = { + creevey: { + skip: { in: /^(?!\b(chrome|chromeDark|chrome2022|chrome2022Dark)\b)/ }, + }, +}; + +export const PagingDisabledForwardLink = () => { + return ; +}; +PagingDisabledForwardLink.parameters = { + creevey: { + skip: { in: /^(?!\b(chrome|chromeDark|chrome2022|chrome2022Dark)\b)/ }, + }, +}; + +export const PlaygroundStory = () => ; +PlaygroundStory.storyName = 'Playground'; +PlaygroundStory.parameters = { creevey: { skip: true } }; + +interface PlaygroundState { + useGlobalListener: boolean; +} +class Playground extends React.Component { + public state: PlaygroundState = { + useGlobalListener: true, + }; + + public render() { + return ( +
+

+

{lorem}

+

+ +

+

+ + + + + +

+

+ +

+ +
+ ); + } + + private handleChangeGlobalListener = (event: React.ChangeEvent) => { + this.setState({ useGlobalListener: event.target.checked }); + }; + + private log = (event: React.KeyboardEvent) => { + action(event.type)(event.key); + }; +} From 00495ffe986334edcb7f7d776b34e73bafb11020 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Tue, 14 May 2024 14:16:18 +0500 Subject: [PATCH 047/197] chore: fix PasswordInput test --- .../__creevey__/PasswordInput.creevey.ts | 43 +++++++++++++++ .../__stories__/PasswordInput.stories.tsx | 53 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 packages/react-ui/components/PasswordInput/__creevey__/PasswordInput.creevey.ts create mode 100644 packages/react-ui/components/PasswordInput/__stories__/PasswordInput.stories.tsx diff --git a/packages/react-ui/components/PasswordInput/__creevey__/PasswordInput.creevey.ts b/packages/react-ui/components/PasswordInput/__creevey__/PasswordInput.creevey.ts new file mode 100644 index 00000000000..a8634f0cb12 --- /dev/null +++ b/packages/react-ui/components/PasswordInput/__creevey__/PasswordInput.creevey.ts @@ -0,0 +1,43 @@ +import { story, kind, test } from 'creevey'; + +kind('PasswordInput', () => { + story('Plain', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + // TODO @Khlutkova fix after update browsers + 'story-skip-0': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['With visible password'], + }, + 'flickering screenshot': { in: ['chrome2022'], tests: ['With typed password'] }, + }, + }); + + test('Plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); + }); + + test('With typed password', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[type="password"]' })) + .sendKeys('Test...') + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('With typed password'); + }); + + test('With visible password', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[type="password"]' })) + .sendKeys('Test...') + .click(this.browser.findElement({ css: '[data-tid="PasswordInputEyeIcon"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('With visible password'); + }); + }); +}); diff --git a/packages/react-ui/components/PasswordInput/__stories__/PasswordInput.stories.tsx b/packages/react-ui/components/PasswordInput/__stories__/PasswordInput.stories.tsx new file mode 100644 index 00000000000..59fe20c0e5a --- /dev/null +++ b/packages/react-ui/components/PasswordInput/__stories__/PasswordInput.stories.tsx @@ -0,0 +1,53 @@ +import React from 'react'; + +import { Story } from '../../../typings/stories'; +import { PasswordInput } from '../PasswordInput'; +import { Nullable } from '../../../typings/utility-types'; + +interface ComponentProps { + capsLockEnabled?: boolean; +} +interface ComponentState { + value: string; +} +class Component extends React.Component { + public state: ComponentState = { + value: '', + }; + + private _passwordInput: Nullable; + + public componentDidMount() { + if (this.props.capsLockEnabled) { + this.setState({ value: 'test' }); + if (this._passwordInput) { + this._passwordInput.setState({ capsLockEnabled: true }); + } + } + } + + public render() { + return ( +
+ { + this._passwordInput = ref; + }} + value={this.state.value} + onValueChange={this._handleChange} + /> +
+ ); + } + + private _handleChange = (value: string) => { + this.setState({ value }); + }; +} + +export default { title: 'PasswordInput' }; + +export const Plain: Story = () => ; +export const CapsLockLabel = () => ; +CapsLockLabel.storyName = 'CapsLock label'; From 7d06d93a2df25d8965f3e902c9fe7ecb903d83a0 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Tue, 14 May 2024 14:52:03 +0500 Subject: [PATCH 048/197] chore: fix Radio test --- .../Radio/__creevey__/Radio.creevey.ts | 27 +++++ .../Radio/__stories__/Radio.stories.tsx | 104 ++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 packages/react-ui/components/Radio/__creevey__/Radio.creevey.ts create mode 100644 packages/react-ui/components/Radio/__stories__/Radio.stories.tsx diff --git a/packages/react-ui/components/Radio/__creevey__/Radio.creevey.ts b/packages/react-ui/components/Radio/__creevey__/Radio.creevey.ts new file mode 100644 index 00000000000..eebbd8e3ec2 --- /dev/null +++ b/packages/react-ui/components/Radio/__creevey__/Radio.creevey.ts @@ -0,0 +1,27 @@ +import { story, kind, test } from 'creevey'; + +kind('Radio', () => { + story('Highlighted', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + flaky: { in: /firefox/ }, + }, + }); + + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('tabPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'body' })) + .sendKeys(this.keys.TAB) + .pause(500) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); + }); + }); +}); diff --git a/packages/react-ui/components/Radio/__stories__/Radio.stories.tsx b/packages/react-ui/components/Radio/__stories__/Radio.stories.tsx new file mode 100644 index 00000000000..db8bf36027f --- /dev/null +++ b/packages/react-ui/components/Radio/__stories__/Radio.stories.tsx @@ -0,0 +1,104 @@ +// TODO: Rewrite stories and enable rule (in process of functional refactoring). +/* eslint-disable react/no-unstable-nested-components */ +import React from 'react'; + +import { Meta, Story } from '../../../typings/stories'; +import { Gapped } from '../../Gapped'; +import { Radio } from '../Radio'; + +export default { + title: 'Radio', + parameters: { + creevey: { + skip: { + 'kind-skip-0': { stories: 'Playground' }, + }, + }, + }, +} as Meta; + +export const RadioWithDifferentStates = () => ( +
+ + + + + + + + + + +
+); +RadioWithDifferentStates.storyName = 'Radio with different states'; +RadioWithDifferentStates.parameters = { + creevey: { + skip: { + 'story-skip-0': { in: ['chromeFlat8px'] }, + }, + }, +}; + +export const Playground = () => { + class Comp extends React.Component { + public state = { + hovered: false, + checked: false, + active: false, + value: 'value', + }; + + public render() { + return ( +
+
+ + + +
+
+ ); + } + + private handleClick = () => { + this.setState({ checked: !this.state.checked }); + }; + } + + return ; +}; + +export const Highlighted: Story = () => { + return ( +
+
+ +
+
+ +
+
+ +
+
+ ); +}; + +export const Size: Story = () => { + return ( +
+ + + Size: small + + + Size: medium + + + Size: large + + +
+ ); +}; From 8947b1165fd675a6ab2b36c53a945d9fe52e72fc Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Tue, 14 May 2024 14:54:38 +0500 Subject: [PATCH 049/197] chore: fix RadioGroup test --- .../__creevey__/RadioGroup.creevey.ts | 85 ++++++++ .../__stories__/RadioGroup.stories.tsx | 197 ++++++++++++++++++ 2 files changed, 282 insertions(+) create mode 100644 packages/react-ui/components/RadioGroup/__creevey__/RadioGroup.creevey.ts create mode 100644 packages/react-ui/components/RadioGroup/__stories__/RadioGroup.stories.tsx diff --git a/packages/react-ui/components/RadioGroup/__creevey__/RadioGroup.creevey.ts b/packages/react-ui/components/RadioGroup/__creevey__/RadioGroup.creevey.ts new file mode 100644 index 00000000000..e43ca3cff3a --- /dev/null +++ b/packages/react-ui/components/RadioGroup/__creevey__/RadioGroup.creevey.ts @@ -0,0 +1,85 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('RadioGroup', () => { + story('Vertical', ({ setStoryParameters }) => { + setStoryParameters({ + captureElement: '#RadioGroup-wrap', + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'hovered' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hovered', 'clicked'] }, + }, + }); + + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('hovered', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: '[data-comp-name~="RadioGroup"] > span > label' }), + }) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); + }); + + test('clicked', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="RadioGroup"] > span > label' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); + }); + + test('mouseLeave', async function () { + // NOTE Firefox bug if click send right after click from previous test it results as double click + await delay(500); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="RadioGroup"] > span > label' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="JustButton"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('mouseLeave'); + }); + + test('tabPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="JustButton"]' })) + .sendKeys(this.keys.TAB) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); + }); + + test('arrow_down', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="JustButton"]' })) + .sendKeys(this.keys.TAB) + .pause(100) + .sendKeys(this.keys.DOWN) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('arrow_down'); + }); + }); +}); diff --git a/packages/react-ui/components/RadioGroup/__stories__/RadioGroup.stories.tsx b/packages/react-ui/components/RadioGroup/__stories__/RadioGroup.stories.tsx new file mode 100644 index 00000000000..cac414d5b4d --- /dev/null +++ b/packages/react-ui/components/RadioGroup/__stories__/RadioGroup.stories.tsx @@ -0,0 +1,197 @@ +import React from 'react'; + +import { Story } from '../../../typings/stories'; +import { RadioGroup } from '../RadioGroup'; +import { Radio } from '../../Radio'; +import { Gapped } from '../../Gapped'; +import { Button } from '../../Button'; +import { Nullable } from '../../../typings/utility-types'; +import { RadioGroupProps } from '..'; + +interface ComponentState { + value: string; +} +class Component extends React.Component> { + public state: ComponentState = { + value: '', + }; + + private _radioGroup: Nullable>; + + public render() { + return ( + + +
+ + ref={(element) => (this._radioGroup = element)} + value={this.state.value} + onValueChange={this.handleValueChange} + {...this.props} + /> +
+ +
+ ); + } + + private handleValueChange = (value: string) => { + this.setState({ value }); + }; +} + +export default { title: 'RadioGroup' }; + +export const Vertical: Story = () => { + return ; +}; +Vertical.storyName = 'vertical'; + +export const Inline = () => ; +Inline.storyName = 'inline'; + +Inline.parameters = { + creevey: { + captureElement: '#RadioGroup-wrap', + }, +}; + +export const WithRenderItem = () => ( + items={['One', 'Two']} renderItem={(x) =>
Value: {x}
} /> +); +WithRenderItem.storyName = 'with renderItem'; +WithRenderItem.parameters = { creevey: { skip: true } }; + +export const MultipleGroups = () => ( +
+ +
+ +
+ +
+); +MultipleGroups.storyName = 'multiple groups'; +MultipleGroups.parameters = { creevey: { skip: true } }; + +export const UncontrolledWithDefaultValue = () => ; +UncontrolledWithDefaultValue.storyName = 'uncontrolled with defaultValue'; +UncontrolledWithDefaultValue.parameters = { creevey: { skip: true } }; + +export const UncontrolledWithChildrenAndDefaultValue = () => ( + + + First element + Second element + Third element + + +); +UncontrolledWithChildrenAndDefaultValue.storyName = 'uncontrolled with children and default value'; +UncontrolledWithChildrenAndDefaultValue.parameters = { creevey: { skip: true } }; + +export const UncontrolledWithChildrenAndDifferentItemStates = () => ( + + + First element + + Second element + + + Warning element + + + Error element + + + +); +UncontrolledWithChildrenAndDifferentItemStates.storyName = 'uncontrolled with children and different item states'; +UncontrolledWithChildrenAndDifferentItemStates.parameters = { creevey: { skip: true } }; + +export const DisabledUncontrolledWithChildren = () => ( + + + First element + Second element + Third element + + +); +DisabledUncontrolledWithChildren.storyName = 'disabled uncontrolled with children'; +DisabledUncontrolledWithChildren.parameters = { creevey: { skip: true } }; + +export const ErrorUncontrolledWithChildren = () => ( + + + First element + Second element + Third element + + +); +ErrorUncontrolledWithChildren.storyName = 'error uncontrolled with children'; +ErrorUncontrolledWithChildren.parameters = { creevey: { skip: true } }; + +export const WarningUncontrolledWithChildren = () => ( + + + First element + Second element + Third element + + +); +WarningUncontrolledWithChildren.storyName = 'warning uncontrolled with children'; +WarningUncontrolledWithChildren.parameters = { creevey: { skip: true } }; + +export const NestedUncontrolledGroupsWithChildren = () => ( + + + First element + + Second element + + Third element + + + First element + Second element + + + First element + + Second element + + Third element + + + Third element + + + Fourth element + Fifth element + + +); +NestedUncontrolledGroupsWithChildren.storyName = 'nested uncontrolled groups with children'; +NestedUncontrolledGroupsWithChildren.parameters = { creevey: { skip: true } }; + +export const Disabled = () => ( + + + First element + Second element + Third element + + +); +Disabled.storyName = 'disabled'; From b5b729297101e16bf20ad08497ddab6516609161 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Tue, 14 May 2024 15:15:48 +0500 Subject: [PATCH 050/197] chore: fix ScrollContainer test --- .../__creevey__/ScrollContainer.creevey.ts | 271 +++++++++++ .../__stories__/ScrollContainer.stories.tsx | 433 ++++++++++++++++++ 2 files changed, 704 insertions(+) create mode 100644 packages/react-ui/components/ScrollContainer/__creevey__/ScrollContainer.creevey.ts create mode 100644 packages/react-ui/components/ScrollContainer/__stories__/ScrollContainer.stories.tsx diff --git a/packages/react-ui/components/ScrollContainer/__creevey__/ScrollContainer.creevey.ts b/packages/react-ui/components/ScrollContainer/__creevey__/ScrollContainer.creevey.ts new file mode 100644 index 00000000000..67aadd5455c --- /dev/null +++ b/packages/react-ui/components/ScrollContainer/__creevey__/ScrollContainer.creevey.ts @@ -0,0 +1,271 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('ScrollContainer', () => { + story('WithDynamicContent', ({ setStoryParameters }) => { + setStoryParameters({ captureElement: '#test-container' }); + + test('changeContent', async function () { + const idle = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#add' })) + .perform(); + const addContent = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scroll50' })) + .perform(); + const scroll50 = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scroll100' })) + .perform(); + const scroll100 = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#remove' })) + .perform(); + const removeContent = await this.takeScreenshot(); + await this.expect({ idle, addContent, scroll50, scroll100, removeContent }).to.matchImages(); + }); + }); + + story('WithOnlyCustomHorizontalScroll', ({ setStoryParameters }) => { + setStoryParameters({ captureElement: '#test-container' }); + + test('moveScroll', async function () { + const idle = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scroll50' })) + .perform(); + const scroll50 = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scroll100' })) + .perform(); + const scroll100 = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scroll0' })) + .perform(); + const scroll0 = await this.takeScreenshot(); + await this.expect({ idle, scroll50, scroll100, scroll0 }).to.matchImages(); + }); + + test('changeContent', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#add' })) + .perform(); + const addContent = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scroll50' })) + .perform(); + const scroll50 = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scroll100' })) + .perform(); + const scroll100 = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scroll0' })) + .perform(); + const scroll0 = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#remove' })) + .perform(); + const removeContent = await this.takeScreenshot(); + await this.expect({ addContent, scroll50, scroll100, scroll0, removeContent }).to.matchImages(); + }); + }); + + story('WithScrollTo', ({ setStoryParameters }) => { + setStoryParameters({ captureElement: '#test-container' }); + + test('scrollTo', async function () { + const idle = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scrollTo' })) + .perform(); + const scrollTo = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scrollToTop' })) + .perform(); + const scrollToTop = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scrollToLeft' })) + .perform(); + const scrollToLeft = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scrollToBottom' })) + .perform(); + const scrollToBottom = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scrollToRight' })) + .perform(); + const scrollToRight = await this.takeScreenshot(); + await this.expect({ + idle, + scrollTo, + scrollToTop, + scrollToBottom, + scrollToLeft, + scrollToRight, + }).to.matchImages(); + }); + }); + + story('HideScrollBar', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\b(firefox|chrome)\b)/ } } }); + + test('hideScroll', async function () { + const beforeScroll = await this.takeScreenshot(); + await this.browser.executeScript(function () { + const scrollContainer = window.document.querySelector('[data-tid~="ScrollContainer__inner"]'); + if (scrollContainer) { + scrollContainer.scrollTop = 500; + } + }); + this.browser + .actions({ + bridge: true, + }) + .move({ origin: this.browser.findElement({ css: 'body' }) }); + await delay(200); + const duringScroll = await this.takeScreenshot(); + await delay(3000); + const afterScroll = await this.takeScreenshot(); + await this.expect({ beforeScroll, duringScroll, afterScroll }).to.matchImages(); + }); + }); + + story('ScrollBarVisibleAfterTogglingDisabled', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }); + + test('toggleDisabled', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="disable-button"]' })) + .click(this.browser.findElement({ css: '[data-tid="disable-button"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('toggleDisabled'); + }); + }); + + story('ShowScrollBarOnScroll', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\b(firefox|chrome)\b)/ } } }); + + test('hideScroll', async function () { + const beforeScroll = await this.takeScreenshot(); + await this.browser.executeScript(function () { + const scrollContainer = window.document.querySelector('[data-tid~="ScrollContainer__inner"]'); + if (scrollContainer) { + scrollContainer.scrollTop = 500; + } + }); + this.browser + .actions({ + bridge: true, + }) + .move({ origin: this.browser.findElement({ css: 'body' }) }); + await delay(200); + const duringScroll = await this.takeScreenshot(); + await delay(3000); + const afterScroll = await this.takeScreenshot(); + await this.expect({ beforeScroll, duringScroll, afterScroll }).to.matchImages(); + }); + }); + + story('ShowScrollBarOnHover', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'hover works only in firefox': { in: /^(?!\b(firefox)\b)/ } } }); + + test('hideScroll', async function () { + this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: '[data-tid~="ScrollContainer__root"]' }), + }) + .perform(); + await delay(500); + const hovered = await this.takeScreenshot(); + this.browser + .actions({ + bridge: true, + }) + .move({ x: 1000, y: 700 }) + .perform(); + await delay(3000); + const withoutHover = await this.takeScreenshot(); + await this.expect({ hovered, withoutHover }).to.matchImages(); + }); + }); + story('NeverShowScrollBar', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'themes dont affect logic': { in: /^(?!\b(firefox|chrome)\b)/ } }, + }); + }); + story('OffsetY', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, + }); + }); + story('OffsetX', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, + }); + }); + story('OffsetYAndX', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, + }); + }); +}); diff --git a/packages/react-ui/components/ScrollContainer/__stories__/ScrollContainer.stories.tsx b/packages/react-ui/components/ScrollContainer/__stories__/ScrollContainer.stories.tsx new file mode 100644 index 00000000000..36a32e1bbe1 --- /dev/null +++ b/packages/react-ui/components/ScrollContainer/__stories__/ScrollContainer.stories.tsx @@ -0,0 +1,433 @@ +// TODO: Rewrite stories and enable rule (in process of functional refactoring). +/* eslint-disable react/no-unstable-nested-components */ +import React, { CSSProperties, useState } from 'react'; + +import { + ScrollContainer, + ScrollContainerScrollState, + ScrollContainerScrollStateX, + ScrollContainerScrollStateY, +} from '../ScrollContainer'; +import { Story } from '../../../typings/stories'; +import { Gapped } from '../../Gapped'; +import { ThemeContext } from '../../../lib/theming/ThemeContext'; + +function getItems(count: number) { + const items = []; + for (let i = 0; i < count; i += 1) { + items.push(i); + } + return items; +} + +const wrapperStyle = { + height: '200px', + width: '100px', + border: '1px solid #000', +}; + +const DynamicContent: React.FC< + React.PropsWithChildren<{ + state: ScrollContainerScrollStateY | ScrollContainerScrollStateX; + scroll: (percentage: number) => void; + add: () => void; + remove: () => void; + onChangeScrollYState?: (x: ScrollContainerScrollStateY) => void; + onChangeScrollXState?: (x: ScrollContainerScrollStateX) => void; + }> +> = ({ children, state, scroll, add, remove, onChangeScrollXState, onChangeScrollYState }) => { + return ( + +
+ +
+ + {children} + +
+
scroll state: {state}
+
+
+ + + + + +
+ ); +}; + +export default { title: 'ScrollContainer' }; + +export const WithLargeContentHeight = () => { + return ( +
+ + {getItems(1000).map((i) => ( +
{i}
+ ))} +
+
+ ); +}; +WithLargeContentHeight.storyName = 'with large content height'; + +export const WithHorizontalScroll = () => { + return ( +
+ + {getItems(100).map((i) => ( +
+ {i} +
+ ))} +
+
+ ); +}; + +interface WrapperState { + scrollState: ScrollContainerScrollState; +} +export const WithScrollState = () => { + class Wrapper extends React.Component { + public state: WrapperState = { scrollState: 'top' as ScrollContainerScrollState }; + + public render() { + const commonBlocksStyles: CSSProperties = { + padding: '5px 10px', + position: 'relative', + transition: 'box-shadow 0.2s', + zIndex: 1, + }; + + const headerStyles: CSSProperties = { + boxShadow: this.state.scrollState !== 'top' ? '0 5px 10px rgba(0, 0, 0, 0.2)' : 'none', + ...commonBlocksStyles, + }; + + const footerStyles: CSSProperties = { + boxShadow: this.state.scrollState !== 'bottom' ? 'rgba(0, 0, 0, 0.2) 0px -5px 10px' : 'none', + background: '#f1f1f1', + ...commonBlocksStyles, + }; + + const footerDarkStyles: CSSProperties = { + boxShadow: this.state.scrollState !== 'bottom' ? 'rgba(0, 0, 0, 0.2) 0px -5px 10px' : 'none', + background: '#1f1f1f', + ...commonBlocksStyles, + }; + + const scrollContainerWrapperStyles: CSSProperties = { + ...wrapperStyle, + border: 'none', + padding: '0px 5px', + boxSizing: 'border-box', + }; + + return ( + + {(theme) => { + return ( +
+
header
+
+ + {getItems(20).map((i) => ( +
{i}
+ ))} +
+
+
+ footer +
+
+ ); + }} +
+ ); + } + + private handleScrollStateChange = (scrollState: ScrollContainerScrollState) => { + this.setState({ scrollState }); + }; + } + + return ; +}; +WithScrollState.storyName = 'with scroll state'; + +export const WithDynamicContent: Story = () => { + const [items, setItems] = React.useState(4); + const [state, setState] = React.useState('top'); + const add = () => setItems(items + 1); + const remove = () => setItems(items > 0 ? items - 1 : 0); + const scroll = (percentage: number) => { + const scrollContainer = window.document.querySelector('[data-tid~="ScrollContainer__inner"]'); + if (scrollContainer) { + scrollContainer.scrollTop = (scrollContainer.scrollHeight - scrollContainer.clientHeight) * (percentage / 100); + } + }; + return ( + + {getItems(items).map((i) => ( +
+ {i} +
+ ))} +
+ ); +}; + +export const WithOnlyCustomHorizontalScroll: Story = () => { + const [state, setState] = React.useState('left'); + const [items, setItems] = React.useState(4); + + const add = () => setItems(items + 1); + const remove = () => setItems(items > 0 ? items - 1 : 0); + + const scroll = (percentage: number) => { + const scrollContainer = window.document.querySelector('[data-tid~="ScrollContainer__inner"]'); + if (scrollContainer) { + scrollContainer.scrollLeft = (scrollContainer.scrollWidth - scrollContainer.clientWidth) * (percentage / 100); + } + }; + + return ( + + {getItems(items).map((i) => ( +
+ {i} +
+ ))} +
+ ); +}; + +WithOnlyCustomHorizontalScroll.storyName = 'with only custom horizontal scroll'; + +export const WithScrollTo: Story = () => { + const refScrollContainer = React.useRef(null); + + const countItems = 8; + + const scrollTo = () => refScrollContainer.current?.scrollTo(document.getElementById(`-${countItems - 1}`)); + const scrollToTop = () => refScrollContainer.current?.scrollToTop(); + const scrollToLeft = () => refScrollContainer.current?.scrollToLeft(); + const scrollToRight = () => refScrollContainer.current?.scrollToRight(); + const scrollToBottom = () => refScrollContainer.current?.scrollToBottom(); + + return ( + +
+ + {getItems(countItems).map((i) => ( +
+
+ {-i} +
+
+ {i} +
+
+ ))} +
+
+ + + + + + + +
+ ); +}; + +export const OffsetY: Story = () => ( +
+ + {Array(30) + .fill(null) + .map((_, i) => ( +
{i}
+ ))} +
+
+); + +export const OffsetX = () => ( +
+ +
+ {Array(10) + .fill(null) + .map((_, i) => ( +
+ {i} +
+ ))} +
+
+
+); +export const OffsetYAndX: Story = () => ( +
+ +
+ {Array(30) + .fill(null) + .map((_, i) => ( +
+ {i} +
+ ))} +
+
+
+); + +export const HideScrollBar: Story = () => ( +
+ +
+ {Array(30) + .fill(null) + .map((_, i) => ( +
+ {i} +
+ ))} +
+
+
+); + +export const ScrollBarVisibleAfterTogglingDisabled: Story = () => { + const [isDisabled, setIsDisabled] = useState(false); + + return ( +
+ +
+ {Array(30) + .fill(null) + .map((_, i) => ( +
+ {i} +
+ ))} +
+
+ +
+ ); +}; + +ScrollBarVisibleAfterTogglingDisabled.storyName = 'scroll bar visible after toggling disabled'; + +export const ShowScrollBarOnScroll: Story = () => ( +
+ +
+ {Array(30) + .fill(null) + .map((_, i) => ( +
+ {i} +
+ ))} +
+
+
+); + +export const ShowScrollBarOnHover: Story = () => ( +
+ +
+ {Array(30) + .fill(null) + .map((_, i) => ( +
+ {i} +
+ ))} +
+
+
+); + +export const NeverShowScrollBar: Story = () => ( +
+ +
+ {Array(30) + .fill(null) + .map((_, i) => ( +
+ {i} +
+ ))} +
+
+
+); From c0b0005ef5ad9dede17e11a7f3b6460d5a214cac Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Tue, 14 May 2024 15:22:29 +0500 Subject: [PATCH 051/197] chore: fix Select test --- .../Select/__creevey__/Select.creevey.ts | 304 ++++++++++ .../Select/__stories__/Select.stories.tsx | 521 ++++++++++++++++++ 2 files changed, 825 insertions(+) create mode 100644 packages/react-ui/components/Select/__creevey__/Select.creevey.ts create mode 100644 packages/react-ui/components/Select/__stories__/Select.stories.tsx diff --git a/packages/react-ui/components/Select/__creevey__/Select.creevey.ts b/packages/react-ui/components/Select/__creevey__/Select.creevey.ts new file mode 100644 index 00000000000..ad06bb69fa0 --- /dev/null +++ b/packages/react-ui/components/Select/__creevey__/Select.creevey.ts @@ -0,0 +1,304 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +const clickedTest = () => { + test('clicked', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); + }); +}; + +const selectTests = () => { + test('idle', async function () { + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('idle'); + }); + + test('clickedTest', async function () { + clickedTest; + }); + + test('MenuItem hover', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' }), + }) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('MenuItem hover'); + }); + + test('selected item', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('selected item'); + }); +}; + +kind('Select', () => { + story('Simple', ({ setStoryParameters }) => { + setStoryParameters({ + captureElement: '.dropdown-test-container', + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'MenuItem hover' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['MenuItem hover'] }, + }, + }); + + selectTests(); + }); + + story('MobileWithSearch', () => { + clickedTest(); + }); + + story('MobileWithTitle', () => { + clickedTest(); + }); + + story('MobileWithTitleAndSearch', () => { + clickedTest(); + }); + + story('MobileWithoutTitleAndSearch', () => { + clickedTest(); + }); + + story('UseLink', ({ setStoryParameters }) => { + setStoryParameters({ + captureElement: '.dropdown-test-container', + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'MenuItem hover' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['MenuItem hover'] }, + }, + }); + + selectTests(); + }); + + story('UseLinkWithIcon', ({ setStoryParameters }) => { + setStoryParameters({ + captureElement: '.dropdown-test-container', + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'MenuItem hover' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['MenuItem hover'] }, + }, + }); + + selectTests(); + }); + + story('WithTextOverflow', ({ setStoryParameters }) => { + setStoryParameters({ + captureElement: '.dropdown-test-container', + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'MenuItem hover' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['MenuItem hover'] }, + }, + }); + + selectTests(); + }); + + story('UsingOnKeyDown', () => { + test('press Enter', async function () { + const element = await this.browser.findElement({ css: '.dropdown-test-container' }); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .sendKeys(this.keys.ENTER) + .sendKeys(this.keys.ARROW_DOWN) + .sendKeys(this.keys.ENTER) + .perform(); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('press Enter'); + }); + }); + + story('WithSearchAndVariousWidth', ({ setStoryParameters }) => { + setStoryParameters({ + captureElement: '#test-element', + skip: { + flaky: { in: ['chrome2022', 'chrome2022Dark'] }, + }, + }); + + test('search', async function () { + const root = await this.browser.findElement({ css: '[data-tid="root"]' }); + const select = await this.browser.findElement({ css: '[data-comp-name~="Select"]' }); + await this.browser + .actions({ + bridge: true, + }) + .click(select) + .pause(500) + .perform(); + const plainSearch = await root.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ARROW_DOWN) + .pause(500) + .perform(); + const pressKeyDown = await root.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Input"]' })) + .sendKeys('test') + .pause(500) + .perform(); + const fullFieldSearch = await root.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(select) + .click(select) + .pause(500) + .perform(); + const emptySearch = await root.takeScreenshot(); + await this.expect({ plainSearch, pressKeyDown, fullFieldSearch, emptySearch }).to.matchImages(); + }); + + test('and various width', async function () { + const root = await this.browser.findElement({ css: '[data-tid="root"]' }); + await this.browser + .actions({ bridge: true }) + .click(await this.browser.findElement({ css: '[data-tid="w100px"]' })) + .pause(500) + .perform(); + const w100px = await root.takeScreenshot(); + await this.browser + .actions({ bridge: true }) + .click(await this.browser.findElement({ css: '[data-tid="w300px"]' })) + .pause(500) + .perform(); + const w300px = await root.takeScreenshot(); + await this.browser + .actions({ bridge: true }) + .click(await this.browser.findElement({ css: '[data-tid="w100prc"]' })) + .pause(500) + .perform(); + const w100prc = await root.takeScreenshot(); + await this.expect({ w100px, w300px, w100prc }).to.matchImages(); + }); + }); + + story('WithMenuAlignAndVariousWidth', () => { + test('open', async function () { + const root = await this.browser.findElement({ css: '#test-element' }); + await delay(1000); + await this.expect(await root.takeScreenshot()).to.matchImage(); + }); + }); + + story('WithManualPosition', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } } }); + + test('opened top with portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened top with portal'); + }); + + test('opened bottom with portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom with portal'); + }); + + test('opened top without portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="portal"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened top without portal'); + }); + + test('opened bottom without portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="portal"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom without portal'); + }); + }); + + story('Size', () => { + test('ClickedAll', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="open-all"]' })) + .pause(500) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('ClickedAll'); + }); + }); +}); diff --git a/packages/react-ui/components/Select/__stories__/Select.stories.tsx b/packages/react-ui/components/Select/__stories__/Select.stories.tsx new file mode 100644 index 00000000000..6b9d8faebba --- /dev/null +++ b/packages/react-ui/components/Select/__stories__/Select.stories.tsx @@ -0,0 +1,521 @@ +// TODO: Rewrite stories and enable rule (in process of functional refactoring). +/* eslint-disable react/no-unstable-nested-components */ +import React, { useState } from 'react'; +import AddIcon from '@skbkontur/react-icons/Add'; +import { action } from '@storybook/addon-actions'; +import { CSFStory } from 'creevey'; + +import { Meta, Story } from '../../../typings/stories'; +import { isKeyEnter } from '../../../lib/events/keyboard/identifiers'; +import { Button } from '../../Button'; +import { Select, SelectProps } from '../Select'; +import { Gapped } from '../../Gapped'; +import { ResponsiveLayout } from '../../ResponsiveLayout'; +import { MenuItem } from '../../MenuItem'; + +const mobileDecorator = (Story: () => JSX.Element) => { + return ( +
+ +
+ ); +}; +interface SelectWrapperValue { + label: string; + value: number; +} +interface SelectWrapperState { + value: SelectWrapperValue; +} +class SelectWrapper extends React.Component { + public state: SelectWrapperState = { + value: { label: 'One', value: 1 }, + }; + + public render() { + return ( +
+ + items={[ + { label: 'One', value: 1 }, + { label: 'Two', value: 2 }, + { label: 'Three', value: 3 }, + ]} + value={this.state.value} + onValueChange={(value) => this.setState({ value })} + renderItem={(x) => x.label} + renderValue={(x) => { + if (x) { + return x.label; + } + }} + /> +
+ ); + } +} + +interface ItemsWithCommentsState { + value: number; +} +type ItemWithComments = [number, string, React.ReactNode?]; +class ItemsWithComments extends React.Component { + private static items: ItemWithComments[] = [ + [1, 'ООО Эльбрус', '8387666415 - 113445852'], + [2, 'ИП Иванов Петр', '583662338391'], + [3, 'ЗАО Текстильщики'], + ]; + + public state: ItemsWithCommentsState = { + value: ItemsWithComments.items[0][0], + }; + + public render() { + return ( +
+ + width={200} + value={this.state.value} + items={ItemsWithComments.items} + onValueChange={(value) => this.setState({ value })} + /> +
+ ); + } +} + +type SelectWithNullStateValue = number | null; +interface SelectWithNullState { + value: SelectWithNullStateValue; +} +class SelectWithNull extends React.Component { + public state: SelectWithNullState = { + value: null, + }; + + public render() { + return ( +
+
+ value: {JSON.stringify(this.state.value)} +
+ + items={[[null, 'Any'], Select.SEP, [1, 'First'], [2, 'Second'], [3, 'Third']]} + value={this.state.value} + onValueChange={(value) => this.setState({ value })} + /> +
+ ); + } +} + +export const Simple: Story = () => ( +
+ + )} + setShow({ ...show, showSecond: !show.showSecond })}>With big count of items + {show.showSecond && } + console.log(layout)} /> + + ); +}; +MobileSimple.title = 'Mobile stories'; +MobileSimple.parameters = { + viewport: { + defaultViewport: 'iphone', + }, + creevey: { skip: true }, +}; +MobileSimple.decorators = [ + (Story: () => JSX.Element) => ( +
+
+ +
+
+ ), +]; + +export const MobileWithLongItem: Story = () => { + const longItem = 'Two '.repeat(50); + + return ( +
+ +
+ ); +}; + +MobileWithLongItem.parameters = { + viewport: { + defaultViewport: 'iphone', + }, +}; + +export const MobileWithSearch: Story = () => ( + +); +MobileWithTitle.parameters = { + viewport: { + defaultViewport: 'iphone', + }, +}; +MobileWithTitle.decorators = [mobileDecorator as () => JSX.Element]; + +export const MobileWithTitleAndSearch: Story = () => ( + +); +MobileWithoutTitleAndSearch.parameters = { + viewport: { + defaultViewport: 'iphone', + }, +}; +MobileWithoutTitleAndSearch.decorators = [mobileDecorator as () => JSX.Element]; + +export const Disabled: CSFStory = () => ( + <> + + +); + +Disabled.storyName = 'disabled'; + +export const ComplexValues = () => ; +ComplexValues.storyName = 'Complex values'; +ComplexValues.parameters = { creevey: { skip: true } }; + +export const ItemsWithCommentsStory = () => ; +ItemsWithCommentsStory.storyName = 'Items with comments'; +ItemsWithCommentsStory.parameters = { creevey: { skip: true } }; + +export const WithNull = () => ; +WithNull.storyName = 'With null'; +WithNull.parameters = { creevey: { skip: true } }; + +export const UseLink: Story = () => } use="link" items={['one', 'two', 'three']} />; +UseLinkWithIcon.storyName = 'use link with icon'; + +export const WithTextOverflow: Story = () => +
+ +
+ ); + } + + private refSelect: React.RefObject(); + + private handleClick = () => { + if (this.selectElem) { + this.selectElem.focus(); + } + }; + } + + return ; +}; +ExternalFocus.storyName = 'external focus'; +ExternalFocus.parameters = { creevey: { skip: true } }; + +export const UsingOnKeyDown: Story = () => { + class Sample extends React.Component { + public state = { + opened: false, + text: 'wait...', + }; + private button: Button | null = null; + public render() { + return ( +
+ (selectElem = ref)} search width={width} items={['one', 'two', 'three']} /> +
+ ); +}; +WithSearchAndVariousWidth.storyName = 'with search'; + +export const WithMenuAlignAndVariousWidth: Story = () => { + const widths: Array['width']> = [ + undefined, + '80px', + '120px', + '80%', + '120%', + 'calc(100% + 40px)', + ]; + const row: Array>> = [ + { menuAlign: 'right' }, + { menuAlign: 'right', disablePortal: true }, + { menuAlign: 'left' }, + { menuAlign: 'left', disablePortal: true }, + ]; + const renderSelect = (width: SelectProps['width'], props: Partial>) => ( + + + +
+ ); +}; +WithManualPosition.storyName = 'with manual position'; + +export const Size: Story = () => { + const items = ['one', two, 'three']; + let small: Select | null = null; + let medium: Select | null = null; + let large: Select | null = null; + const handleClick = () => { + if (small) { + small.open(); + } + if (medium) { + medium.open(); + } + if (large) { + large.open(); + } + }; + return ( +
+ + + { + medium = element; + }} + /> + {' '} + +
+ , + )} +
+); +TooltipsWithoutWrapperAroundInlineBlockWith50Width.storyName = + 'Tooltips without wrapper around inline-block with 50% width'; + +export const OpenedTooltipWithoutWrapper = () => ( + + Without wrapper + +); +OpenedTooltipWithoutWrapper.storyName = 'Opened tooltip without wrapper'; + +export const TooltipWithExternalDynamicContent: Story = () => ( + +); +TooltipWithExternalDynamicContent.storyName = 'Tooltip with external dynamic content'; + +export const TooltipWithInternalDynamicContent = () => ( + +); +TooltipWithInternalDynamicContent.storyName = 'Tooltip with internal dynamic content'; +TooltipWithInternalDynamicContent.parameters = { creevey: { skip: true } }; + +export const TooltipWithTriggerClick = () => ; +TooltipWithTriggerClick.storyName = 'Tooltip with trigger=click'; +TooltipWithTriggerClick.parameters = { creevey: { skip: true } }; + +export const TooltipWithDynamicAnchor = () => ; +TooltipWithDynamicAnchor.storyName = 'Tooltip with dynamic anchor'; +TooltipWithDynamicAnchor.parameters = { creevey: { skip: true } }; + +export const MultipleTooltipsWithUseWrapperFalse = () => ; +MultipleTooltipsWithUseWrapperFalse.storyName = 'Multiple tooltips with useWrapper=false'; +MultipleTooltipsWithUseWrapperFalse.parameters = { creevey: { skip: true } }; + +export const TooltipWithInputAndSwitchableContent: Story = () => ; +TooltipWithInputAndSwitchableContent.storyName = 'Tooltip with Input and switchable content'; + +export const DynamicTriggersStory: Story = () => ; +DynamicTriggersStory.storyName = 'dynamic triggers'; + +export const RenderInFirstAvailablePosition: Story = () => ( +
+ +
+); +RenderInFirstAvailablePosition.storyName = 'Render in first available position'; + +interface DynamicContentTooltipState { + content: React.ReactNode; + opened: boolean; +} + +class DynamicContentTooltip extends React.Component { + public state: DynamicContentTooltipState = { + content: SMALL_CONTENT, + opened: false, + }; + + public render() { + return ( + + + + ); + } + + private buttonClickHandler = () => { + const getContent = (state: DynamicContentTooltipState) => { + if (state.opened) { + return state.content; + } else if (state.content === SMALL_CONTENT) { + return LARGE_CONTENT; + } + + return SMALL_CONTENT; + }; + + this.setState((state: DynamicContentTooltipState) => ({ + content: getContent(state), + opened: !state.opened, + })); + }; + + private tooltipContentGetter = () => { + return this.state.content; + }; +} + +class TooltipWithInput extends React.Component { + public state = { show: false }; + public render() { + return ( +
+ + this.setState({ show: Boolean(v) })} /> + +
+ ); + } + + public renderContent = () => { + if (this.state.show) { + return {'Content'}; + } + return null; + }; +} + +interface MyCustomTooltipState { + state: TooltipTrigger; +} + +class MyCustomTooltip extends React.Component { + public state: MyCustomTooltipState = { + state: 'hover', + }; + + public render() { + const tooltipProps: Partial = + this.state.state === 'hover' + ? { trigger: 'hover' } + : { + trigger: 'opened', + onCloseRequest: () => this.setState({ state: 'hover' }), + }; + + return ( + 'hola'} {...tooltipProps}> + + + ); + } +} + +class ManualTooltip extends React.Component { + public state: MyCustomTooltipState = { + state: 'opened', + }; + + public render() { + const tooltipProps: Partial = { + trigger: this.state.state, + closeButton: false, + }; + + return ( + 'hola'} {...tooltipProps}> + + + ); + } +} + +const SMALL_CONTENT = Sample text; +function getSmallContent() { + return SMALL_CONTENT; +} +const LARGE_CONTENT = ( + + Sample text, sample text, sample text, sample text, sample text +
+ Sample text, sample text, sample text, sample text, sample text +
+ Sample text, sample text, sample text, sample text, sample text +
+ Sample text, sample text, sample text, sample text, sample text +
+ Sample text, sample text, sample text, sample text, sample text +
+ Sample text, sample text, sample text, sample text, sample text +
+); + +interface HasPopupPositionProps { + pos: PopupPositionsType; +} +interface HasDynamicContentState { + content: React.ReactNode; +} +class ExternalDynamicContentTooltip extends React.Component { + public state: HasDynamicContentState = { + content: SMALL_CONTENT, + }; + + public render() { + return ( + + + + ); + } + + private buttonClickHandler = () => { + this.setState({ + content: this.state.content === SMALL_CONTENT ? LARGE_CONTENT : SMALL_CONTENT, + }); + }; + + private tooltipContentGetter = () => { + return this.state.content; + }; +} + +class TooltipWithDynamicContent extends React.Component { + public state: HasDynamicContentState = { + content: SMALL_CONTENT, + }; + + public render() { + return ( +
+
+ +
+
{this.state.content}
+
+ ); + } + private buttonClickHandler = () => { + this.setState({ + content: this.state.content === SMALL_CONTENT ? LARGE_CONTENT : SMALL_CONTENT, + }); + }; +} + +class InternalDynamicContentTooltip extends React.Component { + public render() { + return ( + + Tooltip anchor + + ); + } + + private tooltipContentGetter = () => { + return ; + }; +} + +class DynamicAnchor extends React.Component { + public state = { + isFirst: true, + }; + public render() { + return this.state.isFirst ? ( + First anchor + ) : ( +
+ Second anchor +
+ ); + } + private onClickHandler = () => { + this.setState({ isFirst: !this.state.isFirst }); + }; +} + +const DYNAMIC_TOOLTIP_POSITIONS: PopupPositionsType[] = [ + 'top left', + 'top left', + 'left middle', + 'bottom left', + 'bottom left', +]; + +interface DynamicContentStoryProps { + TooltipComponentClass: typeof ExternalDynamicContentTooltip | typeof InternalDynamicContentTooltip; +} +const DynamicContentStory = (props: DynamicContentStoryProps) => { + const { TooltipComponentClass } = props; + return ( +
+ {DYNAMIC_TOOLTIP_POSITIONS.map((position, index) => { + return ( +
+ +
+ ); + })} +
+ ); +}; + +function DynamicAnchorTooltip() { + return ( +
+ + + +
+ ); +} + +class TooltipWithClickTrigger extends React.Component { + public render() { + return ( +
+ + Click me + +
+ ); + } + private outerTooltipContentGetter = () => { + return ( + + Item 1 + Item 2 + + Click me for more... + + + ); + }; + private innerTooltipContentGetter = () => { + return ( + + More: + Item 3 + Item 4 + + ); + }; +} + +function MultipleTooltips() { + return ( +
+ + + + + Poor anchor + + + + +
+ ); +} + +interface DynamicTriggersState { + trigger?: TooltipTrigger; +} + +class DynamicTriggers extends React.Component { + public state: DynamicTriggersState = {}; + + public render() { + const triggers: TooltipTrigger[] = ['hover', 'click', 'focus', 'opened', 'closed', 'hoverAnchor', 'hover&focus']; + return ( +
+
+ {triggers.map((trigger) => ( + + ))} +
+ + + +
+ ); + } + + private setTrigger = (trigger: TooltipTrigger) => { + this.setState({ + trigger, + }); + }; +} + +class TestTooltipForManual extends React.Component { + private tooltip: Tooltip | null = null; + public state = { onOpenCalledTimes: 0, onCloseCalledTimes: 0 }; + + render() { + return ( +
+ +
onOpen called {this.state.onOpenCalledTimes} times
+
onClose called {this.state.onCloseCalledTimes} times
+
+ + + + + + 'Opened by Show()'} + trigger="manual" + pos="bottom left" + ref={(element) => { + this.tooltip = element; + }} + onOpen={() => { + this.setState({ onOpenCalledTimes: this.state.onOpenCalledTimes + 1 }); + }} + onClose={() => { + this.setState({ onCloseCalledTimes: this.state.onCloseCalledTimes + 1 }); + }} + > + + +
+ ); + } + + handleClickOnShow() { + if (this.tooltip) { + this.tooltip.show(); + } + } + handleClickOnHide() { + if (this.tooltip) { + this.tooltip.hide(); + } + } +} + +export const TooltipWithManualControl: Story = () => ; +TooltipWithManualControl.storyName = 'manual control'; + +export const TooltipWithIconFromPackage = () => ( + + + +); +TooltipWithIconFromPackage.storyName = 'tooltip with icon'; + +const FunctionalChild = () => { + return
FunctionalChild
; +}; +export const TooltipWithFunctionalChild = () => ( + + + +); +TooltipWithFunctionalChild.storyName = 'tooltip with functional child'; + +const anchorStyle: CSSProperties = { + left: 60, + position: 'absolute', + height: 55, + width: 55, + border: '1px solid #dfdede', +}; + +interface AnchorTooltipExampleState { + anchor: Nullable; +} +class AnchorTooltipExample extends React.Component { + public state: AnchorTooltipExampleState = { + anchor: null, + }; + + render() { + return ( + <> + {this.state.anchor ? ( + 'Hello React'} trigger="hover" /> + ) : null} +
+
this.setState({ anchor: event.target as HTMLElement })} + onMouseLeave={() => this.setState({ anchor: null })} + /> +
this.setState({ anchor: event.target as HTMLElement })} + onMouseLeave={() => this.setState({ anchor: null })} + /> +
+ + ); + } +} + +export const TooltipWithAnchor: Story = () => ; + +TooltipWithAnchor.storyName = 'Tooltip with anchor'; From 255a0b10d487f28488ecac8fa43f0e648bddced1 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Wed, 15 May 2024 13:35:00 +0500 Subject: [PATCH 064/197] chore: fix TooltipMenu test --- .../opened/chrome/opened.png | 0 .../opened/chrome/opened.png | 0 .../__creevey__/TooltipMenu.creevey.ts | 131 +++++++++++++ .../__stories__/TooltipMenu.stories.tsx | 177 ++++++++++++++++++ 4 files changed, 308 insertions(+) rename packages/react-ui/.creevey/images/TooltipMenu/{Functional tests => }/With Items And Icons Without Text Alignment/opened/chrome/opened.png (100%) rename packages/react-ui/.creevey/images/TooltipMenu/{Functional tests => }/With Items And Icons/opened/chrome/opened.png (100%) create mode 100644 packages/react-ui/components/TooltipMenu/__creevey__/TooltipMenu.creevey.ts create mode 100644 packages/react-ui/components/TooltipMenu/__stories__/TooltipMenu.stories.tsx diff --git a/packages/react-ui/.creevey/images/TooltipMenu/Functional tests/With Items And Icons Without Text Alignment/opened/chrome/opened.png b/packages/react-ui/.creevey/images/TooltipMenu/With Items And Icons Without Text Alignment/opened/chrome/opened.png similarity index 100% rename from packages/react-ui/.creevey/images/TooltipMenu/Functional tests/With Items And Icons Without Text Alignment/opened/chrome/opened.png rename to packages/react-ui/.creevey/images/TooltipMenu/With Items And Icons Without Text Alignment/opened/chrome/opened.png diff --git a/packages/react-ui/.creevey/images/TooltipMenu/Functional tests/With Items And Icons/opened/chrome/opened.png b/packages/react-ui/.creevey/images/TooltipMenu/With Items And Icons/opened/chrome/opened.png similarity index 100% rename from packages/react-ui/.creevey/images/TooltipMenu/Functional tests/With Items And Icons/opened/chrome/opened.png rename to packages/react-ui/.creevey/images/TooltipMenu/With Items And Icons/opened/chrome/opened.png diff --git a/packages/react-ui/components/TooltipMenu/__creevey__/TooltipMenu.creevey.ts b/packages/react-ui/components/TooltipMenu/__creevey__/TooltipMenu.creevey.ts new file mode 100644 index 00000000000..7cadd2fd94b --- /dev/null +++ b/packages/react-ui/components/TooltipMenu/__creevey__/TooltipMenu.creevey.ts @@ -0,0 +1,131 @@ +import { story, kind, test } from 'creevey'; + +import { PopupMenuDataTids } from '../../../internal/PopupMenu'; +import { delay } from '../../../lib/utils'; + +const textAlignmentTests = () => { + test('opened', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: `[data-tid~="${PopupMenuDataTids.caption}"]` })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); +}; + +kind('TooltipMenu', () => { + story('SimpleExample', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + // TODO @Khlutkova fix after update browsers + 'story-skip-0': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['clickAfterClickedOnCaption', 'clicked'], + }, + + 'story-skip-1': { in: /(?!\b(firefox)\b)/, tests: ['tabPress'] }, + }, + }); + + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('clickAfterClickedOnCaption', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="PopupMenu"]' })) + .click(this.browser.findElement({ css: '[data-comp-name~="PopupMenu"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('clickAfterClickedOnCaption'); + }); + + test('clicked', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="PopupMenu"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); + }); + + test('clickedOutside', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="PopupMenu"]' })) + .click(this.browser.findElement({ css: 'body' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('clickedOutside'); + }); + + test('tabPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); + }); + + test('enterPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .sendKeys(this.keys.ENTER) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('enterPress'); + }); + + test('escapePress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .sendKeys(this.keys.ENTER) + .sendKeys(this.keys.ESCAPE) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('escapePress'); + }); + }); + + story('MobileExampleHorizontalPaddings', ({ setStoryParameters }) => { + setStoryParameters({ captureElement: null }); + + test('opened', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '#test-element' })) + .perform(); + await delay(200); + await this.browser + .actions({ bridge: true }) + .move({ origin: this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' }) }) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); + }); + story('WithItemsAndIcons', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }); + + textAlignmentTests(); + }); + + story('WithItemsAndIconsWithoutTextAlignment', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }); + + textAlignmentTests(); + }); +}); diff --git a/packages/react-ui/components/TooltipMenu/__stories__/TooltipMenu.stories.tsx b/packages/react-ui/components/TooltipMenu/__stories__/TooltipMenu.stories.tsx new file mode 100644 index 00000000000..71f56194351 --- /dev/null +++ b/packages/react-ui/components/TooltipMenu/__stories__/TooltipMenu.stories.tsx @@ -0,0 +1,177 @@ +import React from 'react'; +import MenuIcon from '@skbkontur/react-icons/Menu'; +import LightbulbIcon from '@skbkontur/react-icons/Lightbulb'; + +import { Meta, Story } from '../../../typings/stories'; +import { MenuItem } from '../../MenuItem'; +import { MenuHeader } from '../../MenuHeader'; +import { MenuSeparator } from '../../MenuSeparator'; +import { TooltipMenu } from '../TooltipMenu'; +import { Button } from '../../Button'; + +export default { + title: 'TooltipMenu', + decorators: [ + (Story: () => JSX.Element) => ( +
+ +
+ ), + ], +} as Meta; + +export const SimpleExample: Story = () => ( + Открыть меню}> + Заголовок меню + + Раз + Два + Три + +); +SimpleExample.storyName = 'Simple example'; + +export const MobileExampleHorizontalPaddings: Story = () => ( + Открыть меню}> + Заголовок меню + + Раз + Два + Три + +); + +MobileExampleHorizontalPaddings.parameters = { + viewport: { + defaultViewport: 'iphone', + }, +}; + +export const ExampleWithWidthOfMenu = () => ( + Открыть меню} menuWidth={300}> + Заголовок меню + + Раз + Два + Три + +); +ExampleWithWidthOfMenu.storyName = 'Example with width of menu'; +ExampleWithWidthOfMenu.parameters = { creevey: { skip: true } }; + +export const ExampleWithMaximumHeightOfMenu = () => ( + Открыть меню} menuMaxHeight={150}> + Заголовок меню + + Раз + Два + Три + +); +ExampleWithMaximumHeightOfMenu.storyName = 'Example with maximum height of menu'; +ExampleWithMaximumHeightOfMenu.parameters = { creevey: { skip: true } }; + +export const CaptionAcceptsAnArbitraryElement = () => ( + + + + } + menuWidth="220px" + > + Раз + Два + Три + +); +CaptionAcceptsAnArbitraryElement.storyName = 'Caption accepts an arbitrary element'; +CaptionAcceptsAnArbitraryElement.parameters = { creevey: { skip: true } }; + +export const MenuInRightPositionOnly = () => ( + + + + } + menuWidth="160px" + positions={['right top', 'right middle', 'right bottom']} + > + Раз + Два + Три + +); +MenuInRightPositionOnly.storyName = 'Menu in right position only'; +MenuInRightPositionOnly.parameters = { creevey: { skip: true } }; + +export const MenuInTopPositionOnlyAlignRight = () => ( + + + + } + menuWidth="150px" + positions={['top right']} + > + Раз + Два + Три + +); +MenuInTopPositionOnlyAlignRight.storyName = 'Menu in top position only, align right'; +MenuInTopPositionOnlyAlignRight.parameters = { creevey: { skip: true } }; + +export const MenuWithoutAnimations = () => ( + Нет анимации}> + Анимация не пройдет + + Я не верю в мультики + +); +MenuWithoutAnimations.storyName = 'Menu without animations'; +MenuWithoutAnimations.parameters = { creevey: { skip: true } }; + +export const WithItemsAndIcons = () => ( +
+ + + + } + > + MenuHeader + }>MenuItem1 + }>MenuItem2 + MenuItem3 + +
+); + +export const WithItemsAndIconsWithoutTextAlignment = () => ( +
+ + + + } + > + MenuHeader + }>MenuItem1 + }>MenuItem2 + MenuItem3 + +
+); From 456603df8d35c621d76a777dfc3b2ff4e3631b48 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Wed, 15 May 2024 13:57:45 +0500 Subject: [PATCH 065/197] chore: fix CloseButtonIcon test --- .../__creevey__/CloseButtonIcon.creevey.ts | 47 +++++++++++++ .../__stories__/CloseButtonIcon.stories.tsx | 66 +++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 packages/react-ui/internal/CloseButtonIcon/__creevey__/CloseButtonIcon.creevey.ts create mode 100644 packages/react-ui/internal/CloseButtonIcon/__stories__/CloseButtonIcon.stories.tsx diff --git a/packages/react-ui/internal/CloseButtonIcon/__creevey__/CloseButtonIcon.creevey.ts b/packages/react-ui/internal/CloseButtonIcon/__creevey__/CloseButtonIcon.creevey.ts new file mode 100644 index 00000000000..2b1474f9513 --- /dev/null +++ b/packages/react-ui/internal/CloseButtonIcon/__creevey__/CloseButtonIcon.creevey.ts @@ -0,0 +1,47 @@ +import { story, kind, test } from 'creevey'; + +const clickThenTAB = (clickDataTid: string) => { + test(clickDataTid, async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: `[data-tid="${clickDataTid}"] input` })) + .pause(500) + .perform(); + const firstFocus = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .pause(500) + .perform(); + const secondFocus = await this.takeScreenshot(); + + await this.expect({ firstFocus, secondFocus }).to.matchImages(); + }); +}; + +kind('CloseButtonIcon', () => { + story('Tabbable', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'do not pass on teamcity': { in: ['firefox2022', 'firefox2022Dark'] }, + 'only available in theme2022': { in: /^(?!\b.*2022.*\b)/ }, + }, + }); + clickThenTAB('notTabbable'); + clickThenTAB('tabbable'); + }); + story('Side', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'only available in theme2022': { in: /^(?!\b.*2022.*\b)/ } }, + }); + }); + story('VerticalAlign', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'only available in theme2022': { in: /^(?!\b.*2022.*\b)/ } }, + }); + }); +}); diff --git a/packages/react-ui/internal/CloseButtonIcon/__stories__/CloseButtonIcon.stories.tsx b/packages/react-ui/internal/CloseButtonIcon/__stories__/CloseButtonIcon.stories.tsx new file mode 100644 index 00000000000..22c9d48a345 --- /dev/null +++ b/packages/react-ui/internal/CloseButtonIcon/__stories__/CloseButtonIcon.stories.tsx @@ -0,0 +1,66 @@ +import React from 'react'; + +import { CloseButtonIcon, CloseButtonIconProps } from '../CloseButtonIcon'; +import { ComponentTable } from '../../ComponentTable'; +import { Gapped } from '../../../components/Gapped'; +import { Story } from '../../../typings/stories'; +import { Input } from '../../../components/Input'; + +export default { + title: 'CloseButtonIcon', +}; + +type CloseButtonIconState = Partial; + +const sizeStates: CloseButtonIconState[] = [{ size: 16 }, { size: 20 }, { size: 24 }, { size: 30 }]; + +const sideStates: CloseButtonIconState[] = [{ side: 16 }, { side: 20 }, { side: 24 }, { side: 30 }]; + +export const Side = () => ( + ({ props }))} + cols={sizeStates.map((props) => ({ props }))} + presetProps={{ style: { background: 'rgba(50, 255, 50, 0.2)' } }} + /> +); + +export const VerticalAlign = () => { + const idle: React.CSSProperties = {}; + const baseline: React.CSSProperties = { display: 'flex', alignItems: 'baseline' }; + const center: React.CSSProperties = { display: 'flex', alignItems: 'center' }; + return ( + + {Object.entries({ idle, baseline, center }).map(([name, style], index) => ( +
+ {name} + + Text + + Text + + Text +
+ ))} +
+ ); +}; + +export const Tabbable: Story = () => { + return ( + +
+ notTabbable + + + +
+
+ tabbable + + + +
+
+ ); +}; From 342929283d6528f1c0994c71abdcacf023239098 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Wed, 15 May 2024 14:02:14 +0500 Subject: [PATCH 066/197] chore: fix ComboBoxView test --- .../__creevey__/ComboBoxView.creevey.ts | 31 +++ .../__stories__/ComboBoxView.stories.tsx | 203 ++++++++++++++++++ 2 files changed, 234 insertions(+) create mode 100644 packages/react-ui/internal/CustomComboBox/__creevey__/ComboBoxView.creevey.ts create mode 100644 packages/react-ui/internal/CustomComboBox/__stories__/ComboBoxView.stories.tsx diff --git a/packages/react-ui/internal/CustomComboBox/__creevey__/ComboBoxView.creevey.ts b/packages/react-ui/internal/CustomComboBox/__creevey__/ComboBoxView.creevey.ts new file mode 100644 index 00000000000..8f1daacc30e --- /dev/null +++ b/packages/react-ui/internal/CustomComboBox/__creevey__/ComboBoxView.creevey.ts @@ -0,0 +1,31 @@ +import { story, kind, test } from 'creevey'; + +const FIREFOX_REGEXP = /.*firefox.*/i; + +kind('ComboBoxView', () => { + story('InputLikeText', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + // TODO @Khlutkova fix after update browsers + 'story-skip-0': { + in: FIREFOX_REGEXP, + tests: ['focused first element'], + }, + }, + }); + + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('focused first element', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('focused first element'); + }); + }); +}); diff --git a/packages/react-ui/internal/CustomComboBox/__stories__/ComboBoxView.stories.tsx b/packages/react-ui/internal/CustomComboBox/__stories__/ComboBoxView.stories.tsx new file mode 100644 index 00000000000..ddba5970c35 --- /dev/null +++ b/packages/react-ui/internal/CustomComboBox/__stories__/ComboBoxView.stories.tsx @@ -0,0 +1,203 @@ +import React from 'react'; +import OkIcon from '@skbkontur/react-icons/'; + +import { Story } from '../../../typings/stories'; +import { ComboBoxView } from '../ComboBoxView'; +import { Gapped } from '../../../components/Gapped'; +import { Modal } from '../../../components/Modal'; +import { MenuItem } from '../../../components/MenuItem'; +import { MenuSeparator } from '../../../components/MenuSeparator'; +import { MenuHeader } from '../../../components/MenuHeader'; + +export default { title: 'ComboBoxView' }; + +export const InputLikeText: Story = () => ( + + + + + + +
+ {' '} + hello +
+
+ {' '} + hello +
+
+ {' '} + hello +
+ + + + +
+ ComboBoxView с правой иконкой в + состоянии загрузки +
+ +
+); +InputLikeText.storyName = 'input like text'; + +export const InputLikeTextWithPlaceholder = () => ( + + + +
+ + Hello +
+
+); +InputLikeTextWithPlaceholder.storyName = 'input like text with placeholder'; + +export const Opened: Story = () => ( + + + + + + + + + + + + + + + +
+ + + +
+ 'Не найдено'} /> + + `Показано ${found} из ${total}`} + /> +
+ null} /> + + Add {query}} + /> +
+); +Opened.storyName = 'opened'; +Opened.parameters = { + creevey: { + skip: { + flacky: { in: ['chrome2022Dark'] }, + }, + }, +}; + +export const WithItems = () => ( +
+ +
+); +WithItems.storyName = 'with items'; + +export const InFlexModal = () => ( + + +
+
+ +
+
+
+
+); +InFlexModal.storyName = 'in flex modal'; +InFlexModal.parameters = { creevey: { captureElement: null } }; + +function simpleRenderValue(value: { value: number; label: string }) { + return value.label; +} + +function complexRenderValue({ id, name }: { id: React.ReactNode; name: React.ReactNode }) { + return ( +
+ {name} + {id} +
+ ); +} + +export const WithCountItems = () => { + const separator = React.useMemo(() => , []); + const items = [ + { id: 1, name: 'one' }, + , + { id: 2, name: 'two' }, + , + { id: 3, name: 'tree' }, + Скоро конец, + { id: 4, name: 'four' }, + separator, + Конец, + ]; + + return ( +
+ complexRenderValue(item as { id: number; name: string })} + renderTotalCount={(found, total) => `Показано ${found} из ${total}`} + /> +
+ ); +}; + +WithCountItems.storyName = 'with total count'; From 35c428a2624e234f338004ffe9a15300cddbf924 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Wed, 15 May 2024 14:06:04 +0500 Subject: [PATCH 067/197] chore: fix FileUploaderFile test --- .../__creevey__/FileUploaderFile.creevey.ts | 25 ++++++++++++ .../__stories__/FileUploaderFile.stories.tsx | 40 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 packages/react-ui/internal/FileUploaderControl/__creevey__/FileUploaderFile.creevey.ts create mode 100644 packages/react-ui/internal/FileUploaderControl/__stories__/FileUploaderFile.stories.tsx diff --git a/packages/react-ui/internal/FileUploaderControl/__creevey__/FileUploaderFile.creevey.ts b/packages/react-ui/internal/FileUploaderControl/__creevey__/FileUploaderFile.creevey.ts new file mode 100644 index 00000000000..5bd74aebf78 --- /dev/null +++ b/packages/react-ui/internal/FileUploaderControl/__creevey__/FileUploaderFile.creevey.ts @@ -0,0 +1,25 @@ +import { story, kind, test } from 'creevey'; + +kind('FileUploaderFile', () => { + story('FileUploaderFileWithValidationError', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { + in: /^(?!\b(chrome)\b)/, + }, + }, + }); + + test('hover', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: '[data-tid="FileUploader__fileName"]' }), + }) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('hover'); + }); + }); +}); diff --git a/packages/react-ui/internal/FileUploaderControl/__stories__/FileUploaderFile.stories.tsx b/packages/react-ui/internal/FileUploaderControl/__stories__/FileUploaderFile.stories.tsx new file mode 100644 index 00000000000..768352472a6 --- /dev/null +++ b/packages/react-ui/internal/FileUploaderControl/__stories__/FileUploaderFile.stories.tsx @@ -0,0 +1,40 @@ +import React from 'react'; + +import { Story } from '../../../typings/stories'; +import { FileUploaderFile } from '../FileUploaderFile/FileUploaderFile'; +import { FileUploaderFileStatus } from '../fileUtils'; + +export default { + title: 'FileUploaderFile', + decorators: [ + (storyFn: () => JSX.Element) => { + return
{storyFn()}
; + }, + ], +}; + +export const FileUploaderFileWithValidationError: Story = () => { + return ( +
+ Promise.resolve(''), + webkitRelativePath: '', + arrayBuffer: () => Promise.resolve(new ArrayBuffer(0)), + slice: () => new Blob(), + stream: () => new ReadableStream(), + }, + status: FileUploaderFileStatus.Error, + validationResult: { isValid: false, message: 'Валидация не прошла' }, + }} + size="small" + /> +
+ ); +}; From d6c2969e186d8e292c322583a57259a40be9ece3 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Wed, 15 May 2024 14:12:52 +0500 Subject: [PATCH 068/197] chore: fix HideBodyVerticalScroll test --- .../HideBodyVerticalScroll.creevey.ts | 57 ++++++++++++++++ .../HideBodyVerticalScroll.stories.tsx | 67 +++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 packages/react-ui/internal/HideBodyVerticalScroll/__creevey__/HideBodyVerticalScroll.creevey.ts create mode 100644 packages/react-ui/internal/HideBodyVerticalScroll/__stories__/HideBodyVerticalScroll.stories.tsx diff --git a/packages/react-ui/internal/HideBodyVerticalScroll/__creevey__/HideBodyVerticalScroll.creevey.ts b/packages/react-ui/internal/HideBodyVerticalScroll/__creevey__/HideBodyVerticalScroll.creevey.ts new file mode 100644 index 00000000000..9ac70cd21f5 --- /dev/null +++ b/packages/react-ui/internal/HideBodyVerticalScroll/__creevey__/HideBodyVerticalScroll.creevey.ts @@ -0,0 +1,57 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +const testScrollLockUnlock = () => { + test('scroll, lock, unlock', async function () { + const toggle = async () => { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="toggle-lock"]' })) + .perform(); + await delay(1000); + }; + await this.browser.executeScript(function () { + const scrollContainer = window.document.documentElement; + scrollContainer.scrollTop = scrollContainer.scrollHeight; + }); + const scrolled = await this.browser.takeScreenshot(); + await toggle(); + const locked = await this.browser.takeScreenshot(); + await toggle(); + const unlocked = await this.browser.takeScreenshot(); + await this.expect({ scrolled, locked, unlocked }).to.matchImages(); + }); +}; + +kind('HideBodyVerticalScroll', () => { + story('Sample', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, + }); + testScrollLockUnlock(); + }); + + story('WithScrollableContent', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, + }); + testScrollLockUnlock(); + }); + + story('WithHTMLOverflowYScroll', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, + }); + testScrollLockUnlock(); + }); + + story('Multiple_WithScrollableContent', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, + }); + testScrollLockUnlock(); + }); +}); diff --git a/packages/react-ui/internal/HideBodyVerticalScroll/__stories__/HideBodyVerticalScroll.stories.tsx b/packages/react-ui/internal/HideBodyVerticalScroll/__stories__/HideBodyVerticalScroll.stories.tsx new file mode 100644 index 00000000000..426da101cd6 --- /dev/null +++ b/packages/react-ui/internal/HideBodyVerticalScroll/__stories__/HideBodyVerticalScroll.stories.tsx @@ -0,0 +1,67 @@ +import React, { useEffect, useState } from 'react'; + +import { HideBodyVerticalScroll } from '../HideBodyVerticalScroll'; +import { Meta, Story } from '../../../typings/stories'; + +export default { + title: 'HideBodyVerticalScroll', +} as Meta; + +const SampleLockScroll = () => { + const [locked, setLocked] = useState(false); + const toggle = () => setLocked((prev) => !prev); + const status = locked ? 'on page' : 'not mounted'; + + return ( +
+
+ + HideBodyVerticalScroll: {status} + {locked && } +
+
+ ); +}; + +export const Sample: Story = () => ( +
+ +
{'s c r o l l . '.repeat(100)}
+
+); + +const renderScrollableContent = () => ( +
+ +
{'s c r o l l . '.repeat(1000)}
+
+); + +export const WithScrollableContent: Story = () => renderScrollableContent(); + +export const WithHTMLOverflowYScroll: Story = () => { + document.documentElement.style.overflowY = 'scroll'; + + useEffect(() => { + return () => { + document.documentElement.style.overflowY = ''; + }; + }, []); + + return ( +
+ +
{'s c r o l l . '.repeat(100)}
+
+ ); +}; +WithHTMLOverflowYScroll.storyName = 'With html.overflowY=scroll'; + +export const Multiple_WithScrollableContent: Story = () => ( + <> + + {renderScrollableContent()} + +); From a02f11b1f481656ab946f57f1e4883ef249222d2 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Wed, 15 May 2024 14:15:37 +0500 Subject: [PATCH 069/197] chore: fix IgnoreLayerClick test --- .../__stories__/IgnoreLayerClick.stories.tsx | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 packages/react-ui/internal/IgnoreLayerClick/__stories__/IgnoreLayerClick.stories.tsx diff --git a/packages/react-ui/internal/IgnoreLayerClick/__stories__/IgnoreLayerClick.stories.tsx b/packages/react-ui/internal/IgnoreLayerClick/__stories__/IgnoreLayerClick.stories.tsx new file mode 100644 index 00000000000..850774022c6 --- /dev/null +++ b/packages/react-ui/internal/IgnoreLayerClick/__stories__/IgnoreLayerClick.stories.tsx @@ -0,0 +1,47 @@ +import React from 'react'; + +import { SidePage } from '../../../components/SidePage'; +import { IgnoreLayerClick } from '../IgnoreLayerClick'; +import { Button } from '../../../components/Button'; +import { Toggle } from '../../../components/Toggle'; + +interface SampleState { + open: boolean; + active: boolean; +} +class Sample extends React.Component { + public state: SampleState = { + active: false, + open: false, + }; + + public render() { + return ( +
+ {this.state.open && ( + this.setState({ open: false })}> + Голова + +
Туловище
+
+
+ )} + + + + + this.setState((state: SampleState) => { + return { active: !state.active }; + }) + } + /> +
+ ); + } +} + +export default { title: 'IgnoreLayerClick', parameters: { creevey: { skip: true } } }; + +export const Common = () => ; From 7e862603e3d6c31667aa8a54564593cc80597744 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Wed, 15 May 2024 14:21:52 +0500 Subject: [PATCH 070/197] chore: fix Menu test --- .../internal/Menu/__creevey__/Menu.creevey.ts | 91 +++++++++ .../Menu/__stories__/Menu.stories.tsx | 176 ++++++++++++++++++ 2 files changed, 267 insertions(+) create mode 100644 packages/react-ui/internal/Menu/__creevey__/Menu.creevey.ts create mode 100644 packages/react-ui/internal/Menu/__stories__/Menu.stories.tsx diff --git a/packages/react-ui/internal/Menu/__creevey__/Menu.creevey.ts b/packages/react-ui/internal/Menu/__creevey__/Menu.creevey.ts new file mode 100644 index 00000000000..b11f1d63e4e --- /dev/null +++ b/packages/react-ui/internal/Menu/__creevey__/Menu.creevey.ts @@ -0,0 +1,91 @@ +import { story, kind, test } from 'creevey'; + +kind('Menu', () => { + story('WithMaxHeight', ({ setStoryParameters }) => { + setStoryParameters({ + captureElement: '[data-tid="menu-container"', + skip: { + flacky: { in: ['chrome2022'] }, + }, + }); + + test('idle', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('idle'); + }); + + test('moved up from top to the last Item', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#move-up' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('moved up from top to the last Item'); + }); + + test('moved up from bottom to the first Item', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#move-up' })) + .click(this.browser.findElement({ css: '#move-up' })) + .click(this.browser.findElement({ css: '#move-up' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('moved up from bottom to the first Item'); + }); + + test('moved down from top to the last Item', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#move-up' })) + .click(this.browser.findElement({ css: '#move-up' })) + .click(this.browser.findElement({ css: '#move-up' })) + .click(this.browser.findElement({ css: '#move-down' })) + .click(this.browser.findElement({ css: '#move-down' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('moved down from top to the last Item'); + }); + + test('moved down from bottom to the first Item', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#move-up' })) + .click(this.browser.findElement({ css: '#move-up' })) + .click(this.browser.findElement({ css: '#move-up' })) + .click(this.browser.findElement({ css: '#move-down' })) + .click(this.browser.findElement({ css: '#move-down' })) + .click(this.browser.findElement({ css: '#move-down' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('moved down from bottom to the first Item'); + }); + }); + + story('WithDisabledMenuItem', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + // TODO @Khlutkova fix after update browsers + 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['mouseenter'] }, + }, + }); + + test('mouseenter', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="menuitem-notdisabled"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('mouseenter'); + }); + }); + story('WithItemsWithIconsWithoutTextAlignment', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, + }); + }); +}); diff --git a/packages/react-ui/internal/Menu/__stories__/Menu.stories.tsx b/packages/react-ui/internal/Menu/__stories__/Menu.stories.tsx new file mode 100644 index 00000000000..c155af20dcc --- /dev/null +++ b/packages/react-ui/internal/Menu/__stories__/Menu.stories.tsx @@ -0,0 +1,176 @@ +import React from 'react'; + +import { Meta, Story } from '../../../typings/stories'; +import { OkIcon } from '../../../internal/icons/16px'; +import { Menu } from '../Menu'; +import { MenuItem, MenuItemProps } from '../../../components/MenuItem'; +import { MenuHeader } from '../../../components/MenuHeader'; +import { MenuSeparator } from '../../../components/MenuSeparator'; + +export default { + title: 'Menu', + parameters: { creevey: { captureElement: '#menu-test-container' } }, + decorators: [ + (Story: () => JSX.Element) => ( + + ), + ], +} as Meta; + +export const WithItems = () => ( + + MenuItem1 + MenuItem2 + MenuItem3 + +); +WithItems.storyName = 'with Items'; + +export const WithItemsWithIcons = () => ( + + MenuHeader + }>MenuItem1 + }>MenuItem2 + MenuItem3 + +); + +export const WithItemsWithIconsWithoutTextAlignment = () => ( + + MenuHeader + }>MenuItem1 + }>MenuItem2 + MenuItem3 + +); + +export const WithHeader = () => ( + + MenuHeader + MenuItem1 + MenuItem2 + MenuItem3 + +); +WithHeader.storyName = 'with Header'; + +export const WithSeparator = () => ( + + MenuHeader + MenuItem1 + + MenuItem2 + +); +WithSeparator.storyName = 'with Separator'; + +export const WithCustomChild = () => ( + + MenuHeader + MenuItem1 + + MenuItem2 +
+ CustomChild +
+
+); +WithCustomChild.storyName = 'with Custom Child'; + +export const WithMaxHeight: Story = () => ( + + + MenuHeader + MenuItem1 + + MenuItem2 + MenuItem3 + MenuFooter + + +); +WithMaxHeight.storyName = 'with maxHeight'; + +export const WithWidth = () => ( + + MenuHeader + MenuItem1 + + MenuItem2 + LongItem LongItem LongItem LongItem LongItem LongItem + +); +WithWidth.storyName = 'with width'; + +export const WithLongItems = () => ( + + MenuHeaderMenuHeaderMenuHeaderMenuHeader + MenuItem1 MenuItem1 MenuItem1 MenuItem1 MenuItem1 + + MenuItem2 + MenuItem3 + +); +WithLongItems.storyName = 'with long Items'; + +export const WithoutShadow = () => ( + + MenuHeader + MenuItem1 + + MenuItem2 + MenuItem3 + +); +WithoutShadow.storyName = 'without Shadow'; + +export const WithDisabledMenuItem: Story = () => ( + + MenuItem1 + MenuItem2 + +); +WithDisabledMenuItem.storyName = 'with disabled MenuItem'; + +class MoveControls extends React.Component { + private menu: Menu | null = null; + + public render() { + return ( +
+
+ + +
+
+
+ {React.isValidElement(this.props.children) + ? React.cloneElement(this.props.children, { ref: this.refMenu } as MenuItemProps) + : this.props.children} +
+
+ ); + } + + private refMenu = (el: Menu) => { + this.menu = el; + }; + + private moveUp = () => { + if (this.menu) { + this.menu.up(); + } + }; + + private moveDown = () => { + if (this.menu) { + this.menu.down(); + } + }; +} From 695715935f681cc14d62e2a17b6784aa0d443365 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Wed, 15 May 2024 14:27:19 +0500 Subject: [PATCH 071/197] chore: fix PerformanceMetrics test --- .../PerformanceMetrics.stories.tsx | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 packages/react-ui/internal/PerformanceMetrics/__stories__/PerformanceMetrics.stories.tsx diff --git a/packages/react-ui/internal/PerformanceMetrics/__stories__/PerformanceMetrics.stories.tsx b/packages/react-ui/internal/PerformanceMetrics/__stories__/PerformanceMetrics.stories.tsx new file mode 100644 index 00000000000..f4a76e78cd8 --- /dev/null +++ b/packages/react-ui/internal/PerformanceMetrics/__stories__/PerformanceMetrics.stories.tsx @@ -0,0 +1,46 @@ +import React from 'react'; + +import { PerformanceMetrics } from '../PerformanceMetrics'; +import { Input } from '../../../components/Input'; +import { Tooltip } from '../../../components/Tooltip'; + +function getTooltipContent() { + return 'Tooltip content'; +} +const INPUTS_COUNT = 150; +const INPUT_WIDTH = 50; +const DUMMY = new Array(INPUTS_COUNT).fill(''); +const WRAPPER_STYLES = { marginRight: 10, marginBottom: 10, display: 'inline-block' }; + +const inputs = ( +
+ {DUMMY.map((i, index) => ( +
+ +
+ ))} +
+); + +const inputsWithTooltip = ( +
+ {DUMMY.map((i, index) => ( +
+ + + +
+ ))} +
+); + +export default { title: 'PerformanceMetrics', parameters: { creevey: { skip: true } } }; + +export const BareInputsVsTooltipInput = () => { + return ( +
+ +
+ ); +}; +BareInputsVsTooltipInput.storyName = 'Bare Inputs vs Tooltip+Input'; From d5777937cb5eada97abf704c0d8030031030738b Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Wed, 15 May 2024 14:27:27 +0500 Subject: [PATCH 072/197] chore: fix Popup test --- .../Popup/__stories__/Popup.stories.tsx | 612 ++++++++++++++++++ 1 file changed, 612 insertions(+) create mode 100644 packages/react-ui/internal/Popup/__stories__/Popup.stories.tsx diff --git a/packages/react-ui/internal/Popup/__stories__/Popup.stories.tsx b/packages/react-ui/internal/Popup/__stories__/Popup.stories.tsx new file mode 100644 index 00000000000..e2d3a60652b --- /dev/null +++ b/packages/react-ui/internal/Popup/__stories__/Popup.stories.tsx @@ -0,0 +1,612 @@ +import React from 'react'; +import { DropdownProps } from 'react-ui'; + +import { Popup, PopupPositionsType, PopupProps } from '../Popup'; +import { Nullable } from '../../../typings/utility-types'; +import { Tooltip } from '../../../components/Tooltip'; +import { ComboBox } from '../../../components/ComboBox'; +import { Hint } from '../../../components/Hint'; +import { Select } from '../../../components/Select'; +import { RenderLayer } from '../../RenderLayer'; +import { isTestEnv } from '../../../lib/currentEnvironment'; +import { ThemeContext } from '../../../lib/theming/ThemeContext'; + +export default { title: 'Popup' }; + +export const AllPinOpened = () => ; +AllPinOpened.storyName = 'All pin opened'; + +export const AllPinOpenedOnSmallElements = () => ; +AllPinOpenedOnSmallElements.storyName = 'All pin opened on small elements'; + +export const PositioningStory = () => ; +PositioningStory.storyName = 'Positioning'; +PositioningStory.parameters = { creevey: { skip: true } }; + +export const DisableAnimations = () => ( +
+ + +
+); +DisableAnimations.storyName = 'disableAnimations'; +DisableAnimations.parameters = { creevey: { skip: true } }; + +export const HintStory = () => ( +
+ +
+); +HintStory.storyName = 'Hint'; + +export const ToastStory = () => ( +
+ +
+); +ToastStory.storyName = 'Toast'; + +export const SmallWidth = () => ; +SmallWidth.storyName = 'Small width'; + +export const HoverBehaviourStory = () => ; +HoverBehaviourStory.storyName = 'Hover behaviour'; +HoverBehaviourStory.parameters = { creevey: { skip: true } }; + +const AllCases = ({ small, padding }: { small: boolean; padding: string }) => ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + +
+ + + + + + +
+ + + + + + +
+ + + + + + + +
+
+); + +const Positioning = () => ( +
+ + + {new Array(6 * 5).fill(0).map((x, i) => { + return Math.floor(i / 6) % 2 ? ( + + + + ) : ( + + + + + + ); + })} + +
+
+
+ + + + + + + +
+
+); + +class MinWidth extends React.Component { + public state: AlwaysOpenedState = { + anchor: null, + }; + + private anchor: Nullable; + + public componentDidMount() { + this.setState({ + anchor: this.anchor, + }); + } + + public render() { + return ( +
+ (this.anchor = el)}>x + {this.state.anchor && ( + +
+ {'21:00'} +
+
+ )} +
+ ); + } +} + +interface AlwaysOpenedProps { + small: boolean; + positions: PopupPositionsType[]; +} +interface AlwaysOpenedState { + anchor: Nullable; +} +class AlwaysOpened extends React.Component { + public state: AlwaysOpenedState = { + anchor: null, + }; + + private anchor: Nullable; + + public componentDidMount() { + this.setState({ + anchor: this.anchor, + }); + } + + public render() { + const defaultStyle: React.CSSProperties = { + width: '80px', + height: '70px', + margin: '20px', + border: '1px solid black', + textAlign: 'center', + fontSize: '40px', + }; + + const style: React.CSSProperties = this.props.small + ? { + ...defaultStyle, + width: '20', + height: '20', + margin: '50', + } + : defaultStyle; + + return ( + + {(theme) => { + return ( +
+
+ x +
+ {this.state.anchor && ( + +
+ Text +
+
+ )} +
+ ); + }} +
+ ); + } + + private _handleRef = (e: HTMLDivElement) => { + this.anchor = e; + }; +} + +interface PopupWithPositionsProps { + placeholder?: string; + disableAnimations?: boolean; +} +interface PopupWithPositionsState { + opened: boolean; + anchor: Nullable; +} +class PopupWithPositions extends React.Component { + public state: PopupWithPositionsState = { + opened: false, + anchor: null, + }; + + private anchor: Nullable; + + public componentDidMount() { + this.setState({ + anchor: this.anchor, + }); + } + + public render() { + return ( + + {(theme) => { + return ( +
+
+ {this.state.anchor && ( + + +
+ {this.props.placeholder || 'Placeholder'} +
+
+
+ )} +
+ ); + }} + + ); + } + + private _handleRef = (element: HTMLDivElement) => { + this.anchor = element; + }; + + private _handleClick = () => { + const currentOpened = this.state.opened; + this.setState({ opened: !currentOpened }); + }; + + private _clickHandler = () => { + this.setState({ opened: false }); + }; +} + +interface FakeHintProps { + positions: PopupPositionsType[]; + margin: number; +} +interface FakeHintState { + anchor: Nullable; +} +class FakeHint extends React.Component { + public state: FakeHintState = { + anchor: null, + }; + + private anchor: Nullable; + + public componentDidMount() { + this.setState({ + anchor: this.anchor, + }); + } + + public render() { + return ( + + {(theme) => { + return ( +
+
(this.anchor = e)} + style={{ width: '100px', height: '100px', border: '1px solid black' }} + > + Hello +
+ {this.state.anchor && ( + + WorldWorldWorldWorldWorld + + )} +
+ ); + }} +
+ ); + } +} + +interface ToastProps { + positions: PopupPositionsType[]; +} +interface ToastState { + anchor: Nullable; +} +class Toast extends React.Component { + public state: ToastState = { + anchor: null, + }; + + private anchor: Nullable; + + public componentDidMount() { + this.setState({ + anchor: this.anchor, + }); + } + + public render() { + return ( +
+
(this.anchor = e)} style={{ width: '100px', height: '100px', border: '1px solid black' }}> + Hello +
+ {this.state.anchor && ( + + WorldWorldWorldWorldWorld + + )} +
+ ); + } +} + +const renderPopupContent = () => { + return Popup content; +}; + +const COMBOBOX_ITEMS = [ + { value: 1, label: 'First' }, + { value: 2, label: 'Second' }, +]; +const SELECT_ITEMS = COMBOBOX_ITEMS.map((i) => i.label); +const getComboboxItems = () => Promise.resolve(COMBOBOX_ITEMS); + +interface DropdownValue { + value: number; + label: string; +} + +interface HoverTestProps { + dropdownProps?: Pick; + popupProps?: Pick; + useText?: boolean; +} +interface HasDropdownState { + selected?: DropdownValue; +} +class TooltipWithCombobox extends React.Component { + public state: HasDropdownState = {}; + + public render() { + const tooltipProps = this.props.popupProps || {}; + const comboboxProps = this.props.dropdownProps || {}; + return ( + + {this.props.useText ? ( + 'Sample text' + ) : ( + + )} + + ); + } + private handleOnChange = (value: DropdownValue) => { + this.setState({ selected: value }); + }; +} + +class HintWithSelect extends React.Component { + public state: HasDropdownState = {}; + + public render() { + const hintProps = this.props.popupProps || {}; + const selectProps = this.props.dropdownProps || {}; + return ( + + {this.props.useText ? ( + 'Sample text' + ) : ( + + size={'large'} + items={SELECT_ITEMS} + value={this.state.selected} + onValueChange={this.handleOnChange} + {...selectProps} + /> + )} + + ); + } + private handleOnChange = (value: DropdownValue) => { + this.setState({ selected: value }); + }; +} + +const HOVER_CASES: HoverTestProps[] = [ + { + dropdownProps: { disablePortal: true }, + popupProps: { useWrapper: true }, + }, + { + dropdownProps: { disablePortal: true }, + popupProps: { useWrapper: false }, + }, + { + dropdownProps: { disablePortal: false }, + popupProps: { useWrapper: true }, + }, + { + dropdownProps: { disablePortal: false }, + popupProps: { useWrapper: false }, + }, + { + useText: true, + popupProps: { useWrapper: true }, + }, + { + useText: true, + popupProps: { useWrapper: false }, + }, +]; + +const DescribeProps = (props: HoverTestProps) => { + return ( + + {props.useText ? 'Text' : 'Component'} + {props.popupProps &&
} + {props.popupProps && `popupProps.useWrapper=${props.popupProps.useWrapper}`} + {props.dropdownProps &&
} + {props.dropdownProps && `dropdownProps.disablePortal=${props.dropdownProps.disablePortal}`} +
+ ); +}; + +class HoverBehaviour extends React.Component { + public render() { + return ( + + + + + + + + + + {HOVER_CASES.map((props, index) => ( + + + + + + ))} + +
CaseTooltipHint
+ + + + + +
+ ); + } +} From bfe3f4293b2d7a7c504624ba4c9be3e238aa59f5 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Wed, 15 May 2024 14:31:45 +0500 Subject: [PATCH 073/197] chore: fix PopupMenu test --- .../opened/chrome/opened.png | 0 .../opened/chrome/opened.png | 0 .../with Items/opened/chrome/opened.png | 0 .../__creevey__/PopupMenu.creevey.ts | 37 +++++++++++++ .../__stories__/PopupMenu.creevey.stories.tsx | 53 +++++++++++++++++++ 5 files changed, 90 insertions(+) rename packages/react-ui/.creevey/images/PopupMenu/{Functional tests => }/With Items With Icons Without Text Alignment/opened/chrome/opened.png (100%) rename packages/react-ui/.creevey/images/PopupMenu/{Functional tests => }/With Items With Icons/opened/chrome/opened.png (100%) rename packages/react-ui/.creevey/images/PopupMenu/{Functional tests => }/with Items/opened/chrome/opened.png (100%) create mode 100644 packages/react-ui/internal/PopupMenu/__creevey__/PopupMenu.creevey.ts create mode 100644 packages/react-ui/internal/PopupMenu/__stories__/PopupMenu.creevey.stories.tsx diff --git a/packages/react-ui/.creevey/images/PopupMenu/Functional tests/With Items With Icons Without Text Alignment/opened/chrome/opened.png b/packages/react-ui/.creevey/images/PopupMenu/With Items With Icons Without Text Alignment/opened/chrome/opened.png similarity index 100% rename from packages/react-ui/.creevey/images/PopupMenu/Functional tests/With Items With Icons Without Text Alignment/opened/chrome/opened.png rename to packages/react-ui/.creevey/images/PopupMenu/With Items With Icons Without Text Alignment/opened/chrome/opened.png diff --git a/packages/react-ui/.creevey/images/PopupMenu/Functional tests/With Items With Icons/opened/chrome/opened.png b/packages/react-ui/.creevey/images/PopupMenu/With Items With Icons/opened/chrome/opened.png similarity index 100% rename from packages/react-ui/.creevey/images/PopupMenu/Functional tests/With Items With Icons/opened/chrome/opened.png rename to packages/react-ui/.creevey/images/PopupMenu/With Items With Icons/opened/chrome/opened.png diff --git a/packages/react-ui/.creevey/images/PopupMenu/Functional tests/with Items/opened/chrome/opened.png b/packages/react-ui/.creevey/images/PopupMenu/with Items/opened/chrome/opened.png similarity index 100% rename from packages/react-ui/.creevey/images/PopupMenu/Functional tests/with Items/opened/chrome/opened.png rename to packages/react-ui/.creevey/images/PopupMenu/with Items/opened/chrome/opened.png diff --git a/packages/react-ui/internal/PopupMenu/__creevey__/PopupMenu.creevey.ts b/packages/react-ui/internal/PopupMenu/__creevey__/PopupMenu.creevey.ts new file mode 100644 index 00000000000..ee35ece4da7 --- /dev/null +++ b/packages/react-ui/internal/PopupMenu/__creevey__/PopupMenu.creevey.ts @@ -0,0 +1,37 @@ +import { story, kind, test } from 'creevey'; + +import { PopupMenu, PopupMenuDataTids } from '../PopupMenu'; +import { delay } from '../../../lib/utils'; + +const textAlignmentTests = () => { + test('opened', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: `[data-tid~="${PopupMenuDataTids.caption}"]` })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); +}; + +kind('PopupMenu', () => { + story('WithItems', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }); + + textAlignmentTests(); + }); + + story('WithItemsWithIcons', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }); + + textAlignmentTests(); + }); + + story('WithItemsWithIconsWithoutTextAlignment', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }); + + textAlignmentTests(); + }); +}); diff --git a/packages/react-ui/internal/PopupMenu/__stories__/PopupMenu.creevey.stories.tsx b/packages/react-ui/internal/PopupMenu/__stories__/PopupMenu.creevey.stories.tsx new file mode 100644 index 00000000000..5711ff78c9d --- /dev/null +++ b/packages/react-ui/internal/PopupMenu/__stories__/PopupMenu.creevey.stories.tsx @@ -0,0 +1,53 @@ +import React from 'react'; + +import { Meta, Story } from '../../../typings/stories'; +import { OkIcon } from '../../icons/16px'; +import { PopupMenu } from '../PopupMenu'; +import { MenuItem } from '../../../components/MenuItem'; +import { MenuHeader } from '../../../components/MenuHeader'; +import { Button } from '../../../components/Button'; + +export default { + title: 'PopupMenu', + decorators: [ + (Story: () => JSX.Element) => ( +
+ +
+ ), + ], +} as Meta; + +export const WithItems: Story = () => ( + Click me}> + MenuItem1 + MenuItem2 + MenuItem3 + +); +WithItems.storyName = 'with Items'; + +export const WithItemsWithIcons: Story = () => ( + Click me}> + MenuHeader + }>MenuItem1 + }>MenuItem2 + MenuItem3 + +); + +export const WithItemsWithIconsWithoutTextAlignment: Story = () => ( + Click me}> + MenuHeader + }>MenuItem1 + }>MenuItem2 + MenuItem3 + +); From 7a2a58c2de2a62d43b3f52b0649ee69cd7f21ef0 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Wed, 15 May 2024 14:33:09 +0500 Subject: [PATCH 074/197] chore: fix ThemePlayground test --- .../__creevey__/ThemeProvider.creevey.ts | 146 ++++++++++++++++++ .../__stories__/ThemePlayground.stories.tsx | 9 ++ 2 files changed, 155 insertions(+) create mode 100644 packages/react-ui/internal/ThemePlayground/__creevey__/ThemeProvider.creevey.ts create mode 100644 packages/react-ui/internal/ThemePlayground/__stories__/ThemePlayground.stories.tsx diff --git a/packages/react-ui/internal/ThemePlayground/__creevey__/ThemeProvider.creevey.ts b/packages/react-ui/internal/ThemePlayground/__creevey__/ThemeProvider.creevey.ts new file mode 100644 index 00000000000..bf792c98890 --- /dev/null +++ b/packages/react-ui/internal/ThemePlayground/__creevey__/ThemeProvider.creevey.ts @@ -0,0 +1,146 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('ThemeProvider', () => { + story('Playground', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'repeating tests': { + tests: [ + 'default theme top', + 'default theme bottom', + 'dark theme top', + 'dark theme bottom', + 'default old theme top', + 'default old theme bottom', + 'flat old theme top', + 'flat old theme bottom', + 'theme 2022 top', + 'theme 2022 bottom', + 'theme 2022 dark top', + 'theme 2022 dark bottom', + ], + in: /^(?!\b(chrome|firefox)\b)/, + }, + }, + }); + + test('default theme top', async function () { + await this.expect(await this.browser.takeScreenshot()).to.matchImage('default theme top'); + }); + + test('default theme bottom', async function () { + await this.browser.executeScript(function () { + document.documentElement.scrollTop = document.documentElement.scrollHeight; + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('default theme bottom'); + }); + + test('dark theme top', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-prop-id="dark"]' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('dark theme top'); + }); + + test('dark theme bottom', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-prop-id="dark"]' })) + .perform(); + await this.browser.executeScript(function () { + document.documentElement.scrollTop = document.documentElement.scrollHeight; + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('dark theme bottom'); + }); + + test('default old theme top', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-prop-id="defaultOld"]' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('default old theme top'); + }); + + test('default old theme bottom', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-prop-id="defaultOld"]' })) + .perform(); + await this.browser.executeScript(function () { + document.documentElement.scrollTop = document.documentElement.scrollHeight; + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('default old theme bottom'); + }); + + test('flat old theme top', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-prop-id="flatOld"]' })) + .perform(); + await delay(500); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('flat old theme top'); + }); + + test('flat old theme bottom', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-prop-id="flatOld"]' })) + .perform(); + await this.browser.executeScript(function () { + document.documentElement.scrollTop = document.documentElement.scrollHeight; + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('flat old theme bottom'); + }); + + test('theme 2022 top', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-prop-id="theme2022"]' })) + .perform(); + await delay(500); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('theme 2022 top'); + }); + + test('theme 2022 bottom', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-prop-id="theme2022"]' })) + .perform(); + await this.browser.executeScript(function () { + document.documentElement.scrollTop = document.documentElement.scrollHeight; + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('theme 2022 bottom'); + }); + + test('theme 2022 dark top', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-prop-id="theme2022Dark"]' })) + .perform(); + await delay(500); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('theme 2022 dark top'); + }); + + test('theme 2022 dark bottom', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-prop-id="theme2022Dark"]' })) + .perform(); + await this.browser.executeScript(function () { + document.documentElement.scrollTop = document.documentElement.scrollHeight; + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('theme 2022 dark bottom'); + }); + }); +}); diff --git a/packages/react-ui/internal/ThemePlayground/__stories__/ThemePlayground.stories.tsx b/packages/react-ui/internal/ThemePlayground/__stories__/ThemePlayground.stories.tsx new file mode 100644 index 00000000000..e072638c960 --- /dev/null +++ b/packages/react-ui/internal/ThemePlayground/__stories__/ThemePlayground.stories.tsx @@ -0,0 +1,9 @@ +import React from 'react'; + +import { Story } from '../../../typings/stories'; +import { ThemeContextPlayground } from '../ThemeContextPlayground'; + +export default { title: 'ThemeProvider' }; + +export const Playground: Story = () => ; +Playground.storyName = 'playground'; From 8a33651945cfd7b86defd0e32feafd57ee392b6c Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Wed, 15 May 2024 14:38:15 +0500 Subject: [PATCH 075/197] chore: fix ThemeShowcase test --- .../ThemeShowcase/__stories__/ThemeShowcase.stories.tsx | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 packages/react-ui/internal/ThemeShowcase/__stories__/ThemeShowcase.stories.tsx diff --git a/packages/react-ui/internal/ThemeShowcase/__stories__/ThemeShowcase.stories.tsx b/packages/react-ui/internal/ThemeShowcase/__stories__/ThemeShowcase.stories.tsx new file mode 100644 index 00000000000..4ea7af6e88b --- /dev/null +++ b/packages/react-ui/internal/ThemeShowcase/__stories__/ThemeShowcase.stories.tsx @@ -0,0 +1,7 @@ +import React from 'react'; + +import { ThemeShowcase } from '../ThemeShowcase'; + +export default { title: 'ThemeShowcase', parameters: { creevey: { skip: true } } }; + +export const Playground = () => ; From 2c8a16c6b33541e1a1d518796f76bd547e4f7812 Mon Sep 17 00:00:00 2001 From: Elena Ishmatova Date: Wed, 15 May 2024 14:40:25 +0500 Subject: [PATCH 076/197] chore: fix ZIndex test --- .../ZIndex/__creevey__/ZIndex.creevey.ts | 230 +++++ .../ZIndex/__stories__/ZIndex.stories.tsx | 869 ++++++++++++++++++ 2 files changed, 1099 insertions(+) create mode 100644 packages/react-ui/internal/ZIndex/__creevey__/ZIndex.creevey.ts create mode 100644 packages/react-ui/internal/ZIndex/__stories__/ZIndex.stories.tsx diff --git a/packages/react-ui/internal/ZIndex/__creevey__/ZIndex.creevey.ts b/packages/react-ui/internal/ZIndex/__creevey__/ZIndex.creevey.ts new file mode 100644 index 00000000000..8810efaeb68 --- /dev/null +++ b/packages/react-ui/internal/ZIndex/__creevey__/ZIndex.creevey.ts @@ -0,0 +1,230 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; +import { SelectDataTids } from '../../../components/Select'; + +kind('ZIndex', () => { + story('HintAndModalStory', () => { + test('Modal covers hint', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '.modalBody button' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('Modal covers hint'); + }); + }); + + story('BigModalWithLoaderStory', () => { + test('Header covers Loader', async function () { + await this.browser.executeScript(function () { + const sidePage = window.document.querySelector('[data-tid="modal-container"]') as HTMLElement; + + if (sidePage) { + sidePage.scrollTop = sidePage.offsetHeight / 3; + } + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('Header covers Loader'); + }); + }); + + story('TooltipAndSelectStory', () => { + test('Menu covers tooltip', async function () { + const element = await this.browser.findElement({ css: '.container' }); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: `[data-tid=${SelectDataTids.label}]` })) + .sendKeys('q') + .perform(); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('Modal covers hint'); + }); + }); + + story('LoaderInSidePageBody', () => { + test('is covered by Header and Footer', async function () { + await this.browser.executeScript(function () { + const sidePage = window.document.querySelector('[data-tid="SidePage__container"]') as HTMLElement; + + if (sidePage) { + sidePage.scrollTop = sidePage.offsetHeight; + } + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('is covered by Header and Footer'); + }); + }); + + story('SidepageAndSelect', () => { + test('SidePage covers Select and Tooltip', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '.select-container button' })) + .sendKeys('q') + .perform(); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '.open-sidepage-container button' })) + .perform(); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '.sidepage-select-continer button' })) + .sendKeys('q') + .perform(); + const element = await this.browser.findElement({ css: `[data-tid='SidePage__container']` }); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('SidePage covers Select and Tooltip'); + }); + }); + + story('ElementsInLoaderInModalStory', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'flaky test': { + in: ['chrome2022Dark'], + tests: ['Hide Hint on active Loader'], + }, + }, + }); + + test('Open Dropdown while Loader is inactive', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('Open Dropdown while Loader is inactive'); + }); + + test('Hide Hint on active Loader', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-comp-name~="Toggle"]' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('Hide Hint on active Loader'); + }); + }); + + story('LoaderAndSidePageStory', () => { + test('SidePage shadow cover Loader', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-comp-name~="Toggle"]' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('SidePage shadow cover Loader'); + }); + }); + + story('StickyAndTooltipsStory', () => { + test('Sticky covers outside Popup and DropdownContainer', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage( + 'Sticky covers outside Popup and DropdownContainer', + ); + }); + }); + + story('ModalAndToast', () => { + test('toastShown', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-comp-name~="Button"] button' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage(); + }); + }); + + story('ToastOverEverything', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'flickering screenshot': { in: /^(?!\b(firefox))/, tests: 'staticToast' } } }); + + test('staticToast', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid~="static-toast"]' })) + .pause(1000) + .click(this.browser.findElement({ css: 'body' })) + .perform(); + const shown = await this.browser.takeScreenshot(); // Toast rendered by static method doesn't get removed + // when story switches, so we have to close it manually + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid~="ToastView__close"]' })) + .pause(500) + .perform(); + await this.expect(shown).to.matchImage(); + }); + + test('refToast', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid~="ref-toast"]' })) + .pause(1000) + .click(this.browser.findElement({ css: 'body' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage(); + }); + }); + + story('ModalWithDropdown', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } } }); + + test('dropdown overlaps static header', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid="dropdown_top"]' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage(); + }); + + test('dropdown lays under fixed header', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid="dropdown_top"]' })) + .perform(); + await delay(1000); + await this.browser.executeScript(function () { + const scrollContainer = window.document.querySelector('[data-tid="modal-container"]') as HTMLElement; + scrollContainer.scrollTop = scrollContainer.scrollHeight; + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage(); + }); + + test('dropdown lays under fixed footer', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid="dropdown_bottom"]' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage(); + }); + + test('dropdown overlaps static footer', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid="dropdown_bottom"]' })) + .perform(); + await delay(1000); + await this.browser.executeScript(function () { + const scrollContainer = window.document.querySelector('[data-tid="modal-container"]') as HTMLElement; + scrollContainer.scrollTop = scrollContainer.scrollHeight; + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage(); + }); + }); +}); diff --git a/packages/react-ui/internal/ZIndex/__stories__/ZIndex.stories.tsx b/packages/react-ui/internal/ZIndex/__stories__/ZIndex.stories.tsx new file mode 100644 index 00000000000..babb5b5fa87 --- /dev/null +++ b/packages/react-ui/internal/ZIndex/__stories__/ZIndex.stories.tsx @@ -0,0 +1,869 @@ +import React from 'react'; + +import { Dropdown } from '../../../components/Dropdown'; +import { Story } from '../../../typings/stories'; +import { Gapped } from '../../../components/Gapped'; +import { Modal } from '../../../components/Modal'; +import { Loader } from '../../../components/Loader'; +import { Select } from '../../../components/Select'; +import { Kebab } from '../../../components/Kebab'; +import { MenuItem } from '../../../components/MenuItem'; +import { Center } from '../../../components/Center'; +import { Hint, HintProps } from '../../../components/Hint'; +import { Tooltip, TooltipTrigger } from '../../../components/Tooltip'; +import { ZIndex } from '../ZIndex'; +import { Button } from '../../../components/Button'; +import { Toggle } from '../../../components/Toggle'; +import { Popup, PopupPositionsType } from '../../Popup'; +import { Toast } from '../../../components/Toast'; +import { Input } from '../../../components/Input'; +import { SidePage } from '../../../components/SidePage'; +import { ToastView } from '../../../components/Toast/ToastView'; +import { LoaderAndButton } from '../../../components/Loader/__stories__/LoaderAndButton'; +import { DropdownMenu } from '../../../components/DropdownMenu'; +import { Sticky } from '../../../components/Sticky'; +import { ThemeContext } from '../../../lib/theming/ThemeContext'; + +const linearLightGradient = `repeating-linear-gradient( + 60deg, + #fafafa, + #fafafa 20px, + #dfdede 20px, + #dfdede 40px + )`; +const linearDarkGradient = `repeating-linear-gradient( + 60deg, + #868b8e, + #868b8e 20px, + #444 20px, + #444 40px + )`; + +class ZKebab extends React.Component { + public render() { + return ( + + 1 + 2 + 3 + 4 + 5 + 6 + + ); + } +} + +class ZSelect extends React.Component { + public render() { + return + +); + +const ModalWrapper = ({ caption = 'Title', ...props }: { caption?: string; children?: React.ReactChild }) => ( + + {caption} + {props.children} + + +); + +class LoaderCoversTooltip extends React.Component { + public render() { + return ( +
+ +
+ + +
+ ); + } +} + +class ModalWithTooltipInLoader extends React.Component { + public render() { + return ( + +
+ + + +
+
+ ); + } +} + +class TooltipNearLoader extends React.Component { + public render() { + return ( +
+ +
+ + +
+ +
+
+ ); + } +} + +class NestedElementsInLoader extends React.Component { + public renderNestedModal() { + return ( + + + + ); + } + + public render() { + return ( + +
+ +
+ + {this.renderNestedModal()} + +
+
+
+
+ ); + } +} + +interface HintAndModalState { + modalOpened: boolean; + hintOpened: HintProps['opened']; +} +class HintAndModal extends React.Component { + public state: HintAndModalState = { + modalOpened: false, + hintOpened: false, + }; + + public renderModal() { + return ( + + Title + +
+

+ Use rxjs operators with react hooks. Use rxjs operators with react hooksUse rxjs operators with react + hooksUse rxjs operators with react hooksUse rxjs operators with react hooksUse rxjs operators with react + hooksUse rxjs operators with react hooksUse rxjs operators with react hooksUse rxjs operators with react + hooks +

+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ + + +
+ ); + } + + public open = () => { + this.setState({ modalOpened: true }); + }; + + public close = () => { + this.setState({ modalOpened: false }); + }; + + public render() { + return ( +
+ {this.state.modalOpened && this.renderModal()} + + + +
+ ); + } +} + +interface TooltipAndDropdownMenuState { + trigger: TooltipTrigger; +} +class TooltipAndSelect extends React.Component { + public state: TooltipAndDropdownMenuState = { + trigger: 'closed', + }; + + public render() { + const tooltipRender = () => ( +
+ Задача организации, в особенности же рамки и место обучения кадров влечет за собой процесс внедрения и + модернизации форм развития. +
+ ); + + return ( +
+ + + Открыть меню}> + Раз + Два + Три + + + +
+
+ + + Активировать + + + ); + } + + private setActive = (active: boolean) => this.setState({ active }); +} + +class LoaderAndSidePage extends React.Component { + public state = { active: false }; + public render() { + const { active } = this.state; + return ( +
+ + Title + + +

Use rxjs operators with react hooks

+
+
+ + Активировать + +
+ +
+ +
+
+
+ ); + } + private setActive = (active: boolean) => this.setState({ active }); +} + +function ModalInLoaderAndModal() { + return ( +
+ + + 1 + +

Ехал модал через реку

+

Видит модал в реке модал

+

Cунул модал модал в модал

+

Модал модал модал модал

+
+ + + +
+
+ + + 2 + + Ехал модал через реку, видит модал в реке модал, сунул модал модал в модал, модал модал модал модал + + + + + +
+ ); +} + +function StickyAndLoader() { + return ( + <> + + {Array.from({ length: 8 }).map((_, i) => ( +
+

Ехал лоадер через реку

+

Видит лоадер в реке стики

+

Cунул лоадер лоадер в стики

+

Стики лоадер лоадер стики

+
+
+ ))} + +

I'm Sticky inside Loader

+
+
+ +

Sticky outsider

+
+ + ); +} + +function StickyAndTooltips() { + return ( +
+
+
+
Click me!
}> + setMin(e.target.value)} /> - - - - - - - ); -}; -CalendarWithMinMaxDate.storyName = 'Calendar with min max date'; - -CalendarWithMinMaxDate.parameters = { - creevey: { - tests: { - async 'DateSelect months'() { - await delay(1000); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Calendar"]' })) - .perform(); - await delay(1000); - await this.browser - .actions({ bridge: true }) - .click( - this.browser.findElement({ - css: '[data-tid="MonthView__month"]:first-child [data-tid="MonthView__headerMonth"] [data-tid="DateSelect__caption"]', - }), - ) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('DateSelect months'); - }, - async 'DateSelect years'() { - await delay(1000); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Calendar"]' })) - .perform(); - await delay(1000); - await this.browser - .actions({ bridge: true }) - .click( - this.browser.findElement({ - css: '[data-comp-name~="MonthView"]:first-child [data-tid="MonthView__headerYear"] [data-tid="DateSelect__caption"]', - }), - ) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('DateSelect years'); - }, - }, - }, -}; - -export const ScrollsCalendarOnDateChange: Story = () => { - const [date, setDate] = useState('01.01.2001'); - - return ( - <> - - - - ); -}; -ScrollsCalendarOnDateChange.storyName = 'Scrolls Calendar on date change'; - -ScrollsCalendarOnDateChange.parameters = { - creevey: { - tests: { - async 'initial date'() { - await this.expect(await this.takeScreenshot()).to.matchImage('initial date'); - }, - async 'scrolls to new date on date change'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="change-date-button"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('scrolls to new date on date change'); - }, - }, - }, -}; diff --git a/packages/react-ui/components/Calendar/__stories__/Calendar.stories.tsx b/packages/react-ui/components/Calendar/__stories__/Calendar.stories.tsx index 474f4b40a94..df063d780ba 100644 --- a/packages/react-ui/components/Calendar/__stories__/Calendar.stories.tsx +++ b/packages/react-ui/components/Calendar/__stories__/Calendar.stories.tsx @@ -1,7 +1,11 @@ -import React from 'react'; +import React, { useState } from 'react'; +import { action } from '@storybook/addon-actions'; import { Calendar } from '../Calendar'; import { Story } from '../../../typings/stories'; +import { Gapped } from '../../Gapped'; +import { LocaleContext } from '../../../lib/locale'; +import { InternalDateOrder, InternalDateSeparator } from '../../../lib/date/types'; export default { title: 'Calendar' }; @@ -11,12 +15,41 @@ export const CalendarWithBottomSeparator: Story = () => { return ; }; CalendarWithBottomSeparator.storyName = 'Calendar with bottom separator'; -CalendarWithBottomSeparator.parameters = { - creevey: { - skip: { - "8px and 2022 themes don't affect the bottom separator": { - in: /^(?!\b(chrome|chromeDark|firefox|firefoxDark)\b)/, - }, - }, - }, + +export const CalendarWithMinMaxDate: Story = () => { + const [min, setMin] = React.useState('02.07.2017'); + const [max, setMax] = React.useState('30.01.2020'); + + return ( + + + + + + + + ); +}; +CalendarWithMinMaxDate.storyName = 'Calendar with min max date'; + +export const ScrollsCalendarOnDateChange: Story = () => { + const [date, setDate] = useState('01.01.2001'); + + return ( + <> + + + + ); }; +ScrollsCalendarOnDateChange.storyName = 'Scrolls Calendar on date change'; diff --git a/packages/react-ui/components/Calendar/__tests__/Calendar.test.tsx b/packages/react-ui/components/Calendar/__tests__/Calendar.test.tsx index bc55b591436..e8358454fc0 100644 --- a/packages/react-ui/components/Calendar/__tests__/Calendar.test.tsx +++ b/packages/react-ui/components/Calendar/__tests__/Calendar.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, screen, waitFor } from '@testing-library/react'; +import { render, screen, waitFor, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { componentsLocales as DateSelectLocalesRu } from '../../../internal/DateSelect/locale/locales/ru'; @@ -17,10 +17,10 @@ describe('Calendar', () => { expect(screen.getByTestId(CalendarDataTids.root)).toBeInTheDocument(); }); - it('should pass max and min date to year select', () => { + it('should pass max and min date to year select', async () => { render(); - userEvent.click(screen.getAllByTestId('DateSelect__caption')[1]); + await userEvent.click(screen.getAllByTestId('DateSelect__caption')[1]); expect(screen.getByText('2015')).toHaveAttribute('data-prop-disabled', 'true'); expect(screen.getByText('2018')).toHaveAttribute('data-prop-disabled', 'false'); expect(screen.queryByText('2021')).not.toBeInTheDocument(); @@ -86,7 +86,8 @@ describe('Calendar', () => { const date = '1.2.2021'; render(); - expect(screen.getAllByTestId(CalendarDataTids.headerMonth)[0].querySelector('button')).toHaveAttribute( + const monthButton = within(screen.getAllByTestId(CalendarDataTids.headerMonth)[0]).getByRole('button'); + expect(monthButton).toHaveAttribute( 'aria-label', `${DateSelectLocalesRu.selectChosenAriaLabel} ${DateSelectLocalesRu.selectMonthAriaLabel} Февраль`, ); @@ -100,7 +101,8 @@ describe('Calendar', () => { , ); - expect(screen.getAllByTestId(CalendarDataTids.headerMonth)[0].querySelector('button')).toHaveAttribute( + const monthButton = within(screen.getAllByTestId(CalendarDataTids.headerMonth)[0]).getByRole('button'); + expect(monthButton).toHaveAttribute( 'aria-label', `${DateSelectLocalesEn.selectChosenAriaLabel} ${DateSelectLocalesEn.selectMonthAriaLabel} February`, ); @@ -110,7 +112,8 @@ describe('Calendar', () => { const date = '1.2.2021'; render(); - expect(screen.getAllByTestId(CalendarDataTids.headerYear)[0].querySelector('button')).toHaveAttribute( + const yearButton = within(screen.getAllByTestId(CalendarDataTids.headerYear)[0]).getByRole('button'); + expect(yearButton).toHaveAttribute( 'aria-label', `${DateSelectLocalesRu.selectChosenAriaLabel} ${DateSelectLocalesRu.selectYearAriaLabel} 2021`, ); @@ -124,7 +127,8 @@ describe('Calendar', () => { , ); - expect(screen.getAllByTestId(CalendarDataTids.headerYear)[0].querySelector('button')).toHaveAttribute( + const yearButton = within(screen.getAllByTestId(CalendarDataTids.headerYear)[0]).getByRole('button'); + expect(yearButton).toHaveAttribute( 'aria-label', `${DateSelectLocalesEn.selectChosenAriaLabel} ${DateSelectLocalesEn.selectYearAriaLabel} 2021`, ); @@ -138,7 +142,8 @@ describe('Calendar', () => { , ); - expect(screen.getAllByTestId(CalendarDataTids.headerMonth)[0].querySelector('button')).toHaveAttribute( + const monthButton = within(screen.getAllByTestId(CalendarDataTids.headerMonth)[0]).getByRole('button'); + expect(monthButton).toHaveAttribute( 'aria-label', `${DateSelectLocalesRu.selectChosenAriaLabel} ${customAriaLabel} Февраль`, ); @@ -152,7 +157,8 @@ describe('Calendar', () => { , ); - expect(screen.getAllByTestId(CalendarDataTids.headerYear)[0].querySelector('button')).toHaveAttribute( + const yearButton = within(screen.getAllByTestId(CalendarDataTids.headerYear)[0]).getByRole('button'); + expect(yearButton).toHaveAttribute( 'aria-label', `${DateSelectLocalesRu.selectChosenAriaLabel} ${customAriaLabel} 2021`, ); @@ -166,32 +172,32 @@ describe('Calendar', () => { , ); - expect(screen.getAllByTestId(CalendarDataTids.headerYear)[0].querySelector('button')).toHaveAttribute( + const yearButton = within(screen.getAllByTestId(CalendarDataTids.headerYear)[0]).getByRole('button'); + expect(yearButton).toHaveAttribute( 'aria-label', `${customAriaLabel} ${DateSelectLocalesRu.selectYearAriaLabel} 2021`, ); }); - it('month selector sets correct value for aria-expanded', () => { + it('month selector sets correct value for aria-expanded', async () => { render(); - const monthButton = screen.getAllByTestId(CalendarDataTids.headerMonth)[0].querySelector('button') as Element; + const monthButton = within(screen.getAllByTestId(CalendarDataTids.headerMonth)[0]).getByRole('button'); expect(monthButton).toHaveAttribute('aria-expanded', 'false'); - userEvent.click(monthButton); + await userEvent.click(monthButton); expect(monthButton).toHaveAttribute('aria-expanded', 'true'); }); - it('year selector sets correct value for aria-expanded', () => { + it('year selector sets correct value for aria-expanded', async () => { render(); - const yearButton = screen.getAllByTestId(CalendarDataTids.headerYear)[0].querySelector('button') as Element; - + const yearButton = within(screen.getAllByTestId(CalendarDataTids.headerYear)[0]).getByRole('button'); expect(yearButton).toHaveAttribute('aria-expanded', 'false'); - userEvent.click(yearButton); + await userEvent.click(yearButton); expect(yearButton).toHaveAttribute('aria-expanded', 'true'); }); @@ -199,8 +205,8 @@ describe('Calendar', () => { it('month selector has aria-controls attribute', async () => { render(); - const monthButton = screen.getAllByTestId(CalendarDataTids.headerMonth)[0].querySelector('button') as Element; - userEvent.click(monthButton); + const monthButton = within(screen.getAllByTestId(CalendarDataTids.headerMonth)[0]).getByRole('button'); + await userEvent.click(monthButton); expect(monthButton).toHaveAttribute('aria-controls', expect.stringContaining(DateSelectDataTids.menu)); await waitFor(() => { @@ -214,8 +220,8 @@ describe('Calendar', () => { it('year selector has aria-controls attribute', async () => { render(); - const yearButton = screen.getAllByTestId(CalendarDataTids.headerYear)[0].querySelector('button') as Element; - userEvent.click(yearButton); + const yearButton = within(screen.getAllByTestId(CalendarDataTids.headerYear)[0]).getByRole('button'); + await userEvent.click(yearButton); expect(yearButton).toHaveAttribute('aria-controls', expect.stringContaining(DateSelectDataTids.menu)); await waitFor(() => { @@ -229,25 +235,29 @@ describe('Calendar', () => { it('month selector renders button when active', () => { render(); - expect(screen.getAllByTestId(CalendarDataTids.headerMonth)[0].querySelector('button')).toBeInTheDocument(); + const monthButton = within(screen.getAllByTestId(CalendarDataTids.headerMonth)[0]).getByRole('button'); + expect(monthButton).toBeInTheDocument(); }); it('year selector renders button when active', () => { render(); - expect(screen.getAllByTestId(CalendarDataTids.headerYear)[0].querySelector('button')).toBeInTheDocument(); + const yearButton = within(screen.getAllByTestId(CalendarDataTids.headerYear)[0]).getByRole('button'); + expect(yearButton).toBeInTheDocument(); }); it('month selector renders span when disabled', () => { render(); - expect(screen.getAllByTestId(CalendarDataTids.headerMonth)[1].querySelector('span')).toBeInTheDocument(); + const monthButton = within(screen.getAllByTestId(CalendarDataTids.headerMonth)[1]).queryByRole('button'); //с помощью RTL нельзя проверить, что есть спан. Но мы можем проверить, что это не кнопка + expect(monthButton).not.toBeInTheDocument(); }); it('year selector renders span when disabled', () => { render(); - expect(screen.getAllByTestId(CalendarDataTids.headerYear)[1].querySelector('span')).toBeInTheDocument(); + const yearButton = within(screen.getAllByTestId(CalendarDataTids.headerYear)[1]).queryByRole('button'); //с помощью RTL нельзя проверить, что есть спан. Но мы можем проверить, что это не кнопка + expect(yearButton).not.toBeInTheDocument(); }); }); }); diff --git a/packages/react-ui/components/Checkbox/Checkbox.tsx b/packages/react-ui/components/Checkbox/Checkbox.tsx index c2f54bb1c90..9251eb68dbc 100644 --- a/packages/react-ui/components/Checkbox/Checkbox.tsx +++ b/packages/react-ui/components/Checkbox/Checkbox.tsx @@ -1,5 +1,3 @@ -// TODO: Enable this rule in functional components. -/* eslint-disable @typescript-eslint/no-unused-vars */ import React, { AriaAttributes } from 'react'; import PropTypes from 'prop-types'; import { globalObject } from '@skbkontur/global-object'; @@ -198,7 +196,7 @@ export class Checkbox extends React.PureComponent {(theme) => { this.theme = theme; return ( - + {this.renderMain} ); diff --git a/packages/react-ui/components/Checkbox/CheckedIcon.tsx b/packages/react-ui/components/Checkbox/CheckedIcon.tsx index 8f321a77701..f363941ae00 100644 --- a/packages/react-ui/components/Checkbox/CheckedIcon.tsx +++ b/packages/react-ui/components/Checkbox/CheckedIcon.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/display-name */ import React from 'react'; import { iconSizer } from '../../internal/icons2022/iconSizer'; diff --git a/packages/react-ui/components/Checkbox/IndeterminateIcon.tsx b/packages/react-ui/components/Checkbox/IndeterminateIcon.tsx index 0ef04e41154..5a276972357 100644 --- a/packages/react-ui/components/Checkbox/IndeterminateIcon.tsx +++ b/packages/react-ui/components/Checkbox/IndeterminateIcon.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/display-name */ import React from 'react'; import { iconSizer } from '../../internal/icons2022/iconSizer'; diff --git a/packages/react-ui/components/Checkbox/__creevey__/Checkbox.creevey.ts b/packages/react-ui/components/Checkbox/__creevey__/Checkbox.creevey.ts new file mode 100644 index 00000000000..355d31536bd --- /dev/null +++ b/packages/react-ui/components/Checkbox/__creevey__/Checkbox.creevey.ts @@ -0,0 +1,265 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +const checkboxTests = () => { + test('idle', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('idle'); + }); + + test('hovered', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ + css: '[data-tid~="test-checkbox"]', + }), + }) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); + }); + + test('pressed', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ + css: '[data-tid~="test-checkbox"]', + }), + }) + .press() + .pause(1000) + .release() + .perform(); + }); + + test('clicked', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="test-checkbox"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); + }); + + test('tabPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="test-checkbox"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .move({ origin: this.browser.findElement({ css: 'body' }) }) + .press() + .release() + .sendKeys(this.keys.TAB) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); + }); + + test('spacePress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="test-checkbox"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .move({ origin: this.browser.findElement({ css: 'body' }) }) + .press() + .release() + .sendKeys(this.keys.TAB) + .pause(1000) + .sendKeys(this.keys.SPACE) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('spacePress'); + }); +}; + +kind('Checkbox', () => { + story('Plain', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { + in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], + tests: 'hovered', + }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'pressed', 'clicked'], + }, + }, + }); + + checkboxTests(); + }); + + story('Checked', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { + in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], + tests: 'hovered', + }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'pressed', 'clicked'], + }, + }, + }); + test('idle', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('idle'); + }); + + test('hovered', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ + css: '[data-tid~="test-checkbox"]', + }), + }) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); + }); + + test('pressed', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ + css: '[data-tid~="test-checkbox"]', + }), + }) + .press() + .pause(1000) + .release() + .perform(); + }); + }); + + story('Indeterminate', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { + in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], + tests: 'hovered', + }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'clicked'], + }, + }, + }); + + test('plain', async function () { + const element = await this.browser.findElement({ + css: '#screenshot-capture', + }); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('plain'); + }); + + test('hovered', async function () { + const element = await this.browser.findElement({ + css: '#screenshot-capture', + }); + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: 'label' }), + }) + .perform(); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('hovered'); + }); + + test('tabPress', async function () { + const element = await this.browser.findElement({ + css: '#screenshot-capture', + }); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('tabPress'); + }); + + test('clicked', async function () { + const element = await this.browser.findElement({ + css: '#screenshot-capture', + }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'label' })) + .perform(); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('clicked'); + }); + }); + + story('Highlighted', () => { + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('tabPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); + }); + }); + + story('CheckboxLabelSelectionWithPressedShift', () => { + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('selected with pressed shift', async function () { + const checkbox = await this.browser.findElement({ + css: '[data-comp-name~="Checkbox"]', + }); + await this.browser.actions({ bridge: true }).keyDown(this.keys.SHIFT).click(checkbox).perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('selected with pressed shift'); + await this.browser.actions({ bridge: true }).keyUp(this.keys.SHIFT).perform(); + }); + }); +}); diff --git a/packages/react-ui/components/Checkbox/__stories__/Checkbox.stories.tsx b/packages/react-ui/components/Checkbox/__stories__/Checkbox.stories.tsx index 39dada1ee8c..1c03d55c9f8 100644 --- a/packages/react-ui/components/Checkbox/__stories__/Checkbox.stories.tsx +++ b/packages/react-ui/components/Checkbox/__stories__/Checkbox.stories.tsx @@ -1,17 +1,16 @@ import React, { useState } from 'react'; -import { Meta, Story, CreeveyTests } from '../../../typings/stories'; +import { Meta, Story } from '../../../typings/stories'; import { Checkbox } from '../Checkbox'; import { Gapped } from '../../Gapped'; import { Nullable } from '../../../typings/utility-types'; -import { delay } from '../../../lib/utils'; import { SizeProp } from '../../../lib/types/props'; interface PlainCheckboxState { checked: false; size?: SizeProp; } -class PlainCheckbox extends React.Component { +class PlainCheckbox extends React.Component { public state: PlainCheckboxState = { checked: false, }; @@ -35,7 +34,7 @@ interface IndeterminatePlaygroundState { checked: boolean; } -class IndeterminatePlayground extends React.Component { +class IndeterminatePlayground extends React.Component { public state: IndeterminatePlaygroundState = { checked: false, }; @@ -93,118 +92,11 @@ class IndeterminatePlayground extends React.Component { }; } -const checkboxTests: CreeveyTests = { - async idle() { - await this.expect(await this.takeScreenshot()).to.matchImage('idle'); - }, - async hovered() { - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: '[data-tid~="test-checkbox"]' }), - }) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); - }, - async pressed() { - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: '[data-tid~="test-checkbox"]' }), - }) - .press() - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('pressed'); - await this.browser - .actions({ - bridge: true, - }) - .release() - .perform(); - }, - async clicked() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="test-checkbox"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); - }, - async tabPress() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="test-checkbox"]' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .move({ origin: this.browser.findElement({ css: 'body' }) }) - .press() - .release() - .sendKeys(this.keys.TAB) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); - }, - async spacePress() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="test-checkbox"]' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .move({ origin: this.browser.findElement({ css: 'body' }) }) - .press() - .release() - .sendKeys(this.keys.TAB) - .pause(1000) - .sendKeys(this.keys.SPACE) - .pause(1000) - .perform(); - - await this.expect(await this.takeScreenshot()).to.matchImage('spacePress'); - }, -}; - export default { title: 'Checkbox' } as Meta; export const Plain: Story = () => Plain checkbox; Plain.storyName = 'plain'; -Plain.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'hovered' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { - in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], - tests: ['hovered', 'pressed', 'clicked'], - }, - }, - tests: checkboxTests, - }, -}; - export const Unchecked = () => Unchecked; Unchecked.storyName = 'unchecked'; Unchecked.parameters = { creevey: { skip: true } }; @@ -216,25 +108,6 @@ export const Checked = () => ( ); Checked.storyName = 'checked'; -Checked.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'hovered' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { - in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], - tests: ['hovered', 'pressed', 'clicked'], - }, - }, - tests: { - idle: checkboxTests['idle'], - hovered: checkboxTests['hovered'], - pressed: checkboxTests['pressed'], - }, - }, -}; - export const Disabled = () => Disabled; Disabled.storyName = 'disabled'; @@ -320,63 +193,6 @@ ProgrammaticFocus.parameters = { creevey: { skip: true } }; export const Indeterminate: Story = () => Label; Indeterminate.storyName = 'indeterminate'; -Indeterminate.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'hovered' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hovered', 'clicked'] }, - }, - tests: { - async plain() { - const element = await this.browser.findElement({ css: '#screenshot-capture' }); - await delay(1000); - - await this.expect(await element.takeScreenshot()).to.matchImage('plain'); - }, - async hovered() { - const element = await this.browser.findElement({ css: '#screenshot-capture' }); - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: 'label' }), - }) - .perform(); - await delay(1000); - - await this.expect(await element.takeScreenshot()).to.matchImage('hovered'); - }, - async tabPress() { - const element = await this.browser.findElement({ css: '#screenshot-capture' }); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .perform(); - await delay(1000); - - await this.expect(await element.takeScreenshot()).to.matchImage('tabPress'); - }, - async clicked() { - const element = await this.browser.findElement({ css: '#screenshot-capture' }); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'label' })) - .perform(); - await delay(1000); - - await this.expect(await element.takeScreenshot()).to.matchImage('clicked'); - }, - }, - }, -}; - export const Highlighted: Story = () => { return (
@@ -394,27 +210,6 @@ export const Highlighted: Story = () => { }; Highlighted.storyName = 'highlighted'; -Highlighted.parameters = { - creevey: { - tests: { - async plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('plain'); - }, - async tabPress() { - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); - }, - }, - }, -}; - export const CheckboxLabelSelectionWithPressedShift: Story = () => { const [checked, setChecked] = useState(false); @@ -426,25 +221,6 @@ export const CheckboxLabelSelectionWithPressedShift: Story = () => { }; CheckboxLabelSelectionWithPressedShift.storyName = 'checkbox label selection with pressed shift'; -CheckboxLabelSelectionWithPressedShift.parameters = { - creevey: { - tests: { - async plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('plain'); - }, - async 'selected with pressed shift'() { - const checkbox = await this.browser.findElement({ css: '[data-comp-name~="Checkbox"]' }); - - await this.browser.actions({ bridge: true }).keyDown(this.keys.SHIFT).click(checkbox).perform(); - - await this.expect(await this.takeScreenshot()).to.matchImage('selected with pressed shift'); - - await this.browser.actions({ bridge: true }).keyUp(this.keys.SHIFT).perform(); - }, - }, - }, -}; - export const Size: Story = () => { return (
diff --git a/packages/react-ui/components/Checkbox/__tests__/Checkbox-test.tsx b/packages/react-ui/components/Checkbox/__tests__/Checkbox-test.tsx index abed1264689..af14314ed28 100644 --- a/packages/react-ui/components/Checkbox/__tests__/Checkbox-test.tsx +++ b/packages/react-ui/components/Checkbox/__tests__/Checkbox-test.tsx @@ -68,20 +68,20 @@ describe('Checkbox', () => { expect(screen.getByTestId('Checkbox__root')).toHaveTextContent('test'); }); - it('handels onFocus event', () => { + it('handels onFocus event', async () => { const onFocus = jest.fn(); render(); - userEvent.click(screen.getByRole('checkbox')); + await userEvent.click(screen.getByRole('checkbox')); expect(onFocus).toHaveBeenCalledTimes(1); }); - it('handels onBlur event', () => { + it('handels onBlur event', async () => { const onBlur = jest.fn(); render(); - userEvent.click(screen.getByRole('checkbox')); + await userEvent.click(screen.getByRole('checkbox')); screen.getByRole('checkbox').blur(); expect(onBlur).toHaveBeenCalledTimes(1); @@ -101,44 +101,44 @@ describe('Checkbox', () => { expect(onMouseLeave).toHaveBeenCalledTimes(1); }); - it('handels onValueChange event', () => { + it('handels onValueChange event', async () => { const onValueChange = jest.fn(); render(); - userEvent.click(screen.getByRole('checkbox')); + await userEvent.click(screen.getByRole('checkbox')); expect(onValueChange).toHaveBeenCalledTimes(1); }); - it('handels onClick event', () => { + it('handels onClick event', async () => { const onClick = jest.fn(); render(); - userEvent.click(screen.getByRole('checkbox')); + await userEvent.click(screen.getByRole('checkbox')); expect(onClick).toHaveBeenCalledTimes(1); }); - it('click to checkbox children sets state to checkbox', () => { + it('click to checkbox children sets state to checkbox', async () => { render(Обычный чекбокс); expect(screen.getByRole('checkbox')).not.toBeChecked(); - userEvent.click(screen.getByText('Обычный чекбокс')); + await userEvent.click(screen.getByText('Обычный чекбокс')); expect(screen.getByRole('checkbox')).toBeChecked(); }); - it('focuses by tab', () => { + it('focuses by tab', async () => { render(); - userEvent.tab(); + await userEvent.tab(); expect(screen.getByRole('checkbox')).toHaveFocus(); }); - it('uncheck checked checkbox', () => { + it('uncheck checked checkbox', async () => { const checkboxRef = React.createRef(); render(); const checkbox = screen.getByRole('checkbox'); - userEvent.click(checkbox); + await userEvent.click(checkbox); expect(checkbox).toBeChecked(); - userEvent.click(screen.getByRole('checkbox')); + await userEvent.click(screen.getByRole('checkbox')); expect(screen.getByRole('checkbox')).not.toBeChecked(); }); diff --git a/packages/react-ui/components/ComboBox/ComboBox.tsx b/packages/react-ui/components/ComboBox/ComboBox.tsx index 2e9314935d5..b1882480d99 100644 --- a/packages/react-ui/components/ComboBox/ComboBox.tsx +++ b/packages/react-ui/components/ComboBox/ComboBox.tsx @@ -118,7 +118,7 @@ export interface ComboBoxProps * } * }} */ - itemWrapper?: (item: T) => React.ComponentType; + itemWrapper?: (item: T) => React.ComponentType; /** * Функция для отрисовки сообщения о пустом результате поиска diff --git a/packages/react-ui/components/ComboBox/__creevey__/ComboBox.creevey.ts b/packages/react-ui/components/ComboBox/__creevey__/ComboBox.creevey.ts new file mode 100644 index 00000000000..e982c31c04b --- /dev/null +++ b/packages/react-ui/components/ComboBox/__creevey__/ComboBox.creevey.ts @@ -0,0 +1,551 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('ComboBox', () => { + story('SimpleComboboxStory', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { + in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark', 'ie112022', 'ie112022Dark'], + tests: ['hovered', 'selected_2', 'select_1'], + }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered'], + }, + }, + }); + + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('opened', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); + + test('hovered', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ + css: '[data-comp-name~="MenuItem"]:nth-of-type(4)', + }), + }) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); + }); + + test('selected', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ + css: '[data-comp-name~="MenuItem"]:nth-of-type(4)', + }), + }) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .press() + .release() + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('selected'); + }); + + test('search result', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('Second') + .perform(); + await delay(500); + await this.expect(await this.takeScreenshot()).to.matchImage('search result'); + }); + + test('selcted', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('Second') + .pause(1000) + .sendKeys(this.keys.ENTER) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('selcted'); + }); + + test('opened again', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('Second') + .pause(1000) + .sendKeys(this.keys.ENTER) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Input"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('opened again'); + }); + + test('search result_0', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('Такого точно нету') + .perform(); + await delay(500); + await this.expect(await this.takeScreenshot()).to.matchImage('search result_0'); + }); + + test('select', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ARROW_DOWN) + .sendKeys(this.keys.ARROW_DOWN) + .sendKeys(this.keys.ARROW_DOWN) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('select'); + }); + + test('submit', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .pause(1000) + .sendKeys(this.keys.ARROW_DOWN) + .sendKeys(this.keys.ARROW_DOWN) + .sendKeys(this.keys.ARROW_DOWN) + .sendKeys(this.keys.ENTER) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('submit'); + }); + + test('select_1', async function () { + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .pause(500) + .sendKeys('Second') + .pause(500) + .move({ origin: this.browser.findElement({ css: 'body' }) }) + .pause(1000) + .press() + .release() + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('select_1'); + }); + + test('selected_2', async function () { + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .pause(1000) + .sendKeys('Second') + .pause(500) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'body' })) + .perform(); + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('selected_2'); + }); + }); + + story('OpenToTop', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { + in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], + tests: 'hovered', + }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered'], + }, + }, + }); + + test('plain', async function () { + const element = await this.browser.findElement({ + css: '[data-tid="container"]', + }); + await this.expect(await element.takeScreenshot()).to.matchImage('plain'); + }); + + test('opened', async function () { + const element = await this.browser.findElement({ + css: '[data-tid="container"]', + }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.expect(await element.takeScreenshot()).to.matchImage('opened'); + }); + + test('hovered', async function () { + const element = await this.browser.findElement({ + css: '[data-tid="container"]', + }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ + css: '[data-comp-name~="MenuItem"]:nth-of-type(4)', + }), + }) + .perform(); + await this.expect(await element.takeScreenshot()).to.matchImage('hovered'); + }); + + test('selected', async function () { + const element = await this.browser.findElement({ + css: '[data-tid="container"]', + }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ + css: '[data-comp-name~="MenuItem"]:nth-of-type(4)', + }), + }) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .press() + .release() + .perform(); + await this.expect(await element.takeScreenshot()).to.matchImage('selected'); + }); + }); + + story('AlwaysReject', () => { + test('opened', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); + }); + + story('ToogleError', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + flaky: { + in: ['chrome2022', 'chrome2022Dark'], + tests: ['plain again', 'with error'], + }, + }, + }); + + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('with error', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: "[data-comp-name~='Toggle']" })) + .perform(); + await delay(200); + await this.expect(await this.takeScreenshot()).to.matchImage('with error'); + }); + + test('plain again', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: "[data-comp-name~='Toggle']" })) + .pause(200) + .click(this.browser.findElement({ css: "[data-comp-name~='Toggle']" })) + .perform(); + await delay(200); + await this.expect(await this.takeScreenshot()).to.matchImage('plain again'); + }); + }); + + story('WithExternalValue', () => { + test('initial value', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('initial value'); + }); + + test('reset value', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="resetBtn"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('reset value'); + }); + + test('set value', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="resetBtn"]' })) + .click(this.browser.findElement({ css: '[data-tid="setValueBtn"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('set value'); + }); + }); + + story('FocusFlow', () => { + test('before', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('before'); + }); + + test('after Enter on Item', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ENTER) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('after Enter on Item'); + }); + + test('after tab to the next field', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ENTER) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('after tab to the next field'); + }); + }); + + story('WithTooltip', () => { + test('show and hide Tooltip', async function () { + const body = await this.browser.findElement({ css: 'body' }); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid="InputLikeText__input"]' })) + .perform(); + await delay(1000); + const showTooltip = await body.takeScreenshot(); + await this.browser.actions({ bridge: true }).click(body).pause(1000).perform(); + const hideTooltip = await body.takeScreenshot(); + await this.expect({ showTooltip, hideTooltip }).to.matchImages(); + }); + }); + + story('MobileSimple', () => { + test('opened', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid="ComboBoxView__root"]' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('opened'); + }); + }); + + story('WithManualPosition', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } }, + }); + + test('opened top with portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened top with portal'); + }); + + test('opened bottom with portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom with portal'); + }); + + test('opened top without portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="portal"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened top without portal'); + }); + + test('opened bottom without portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="portal"]' })) + .perform(); + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) + .perform(); + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom without portal'); + }); + }); + + story('Size', () => { + test('clicked all', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="open-all"]' })) + .perform(); + await delay(500); + await this.browser.executeScript(function () { + const containers = document.querySelectorAll('[data-tid~="ScrollContainer__inner"]'); + for (let i = 0; i < containers.length; i++) { + containers[i].scrollTop += 300; + } + }); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('ClickedAll'); + }); + }); +}); diff --git a/packages/react-ui/components/ComboBox/__stories__/Combobox.stories.tsx b/packages/react-ui/components/ComboBox/__stories__/Combobox.stories.tsx index 635b4e7d786..8888c704ab2 100644 --- a/packages/react-ui/components/ComboBox/__stories__/Combobox.stories.tsx +++ b/packages/react-ui/components/ComboBox/__stories__/Combobox.stories.tsx @@ -14,11 +14,10 @@ import { Toggle } from '../../Toggle'; import { Button } from '../../Button'; import { Gapped } from '../../Gapped'; import { MenuHeader } from '../../MenuHeader'; -import { delay, mergeRefs } from '../../../lib/utils'; +import { mergeRefs } from '../../../lib/utils'; import { Tooltip } from '../../Tooltip'; import { rootNode, TSetRootNode } from '../../../lib/rootNode'; -// eslint-disable-next-line jest/no-mocks-import const { getCities } = require('../__mocks__/getCities.js'); export default { title: 'ComboBox' } as Meta; @@ -30,251 +29,6 @@ export const SimpleComboboxStory: Story = () => ( ); SimpleComboboxStory.storyName = 'simple combobox'; -SimpleComboboxStory.parameters = { - creevey: { - skip: { - 'story-skip-0': { - in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark', 'ie112022', 'ie112022Dark'], - tests: ['hovered', 'selected_2', 'select_1'], - }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hovered'] }, - }, - tests: { - async plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('plain'); - }, - async opened() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('opened'); - }, - async hovered() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: '[data-comp-name~="MenuItem"]:nth-of-type(4)' }), - }) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); - }, - async selected() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .move({ origin: this.browser.findElement({ css: '[data-comp-name~="MenuItem"]:nth-of-type(4)' }) }) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .press() - .release() - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('selected'); - }, - async 'search result'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys('Second') - .pause(500) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('search result'); - }, - async selcted() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys('Second') - .perform(); - await delay(1000); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.ENTER) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('selcted'); - }, - async 'opened again'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys('Second') - .perform(); - await delay(1000); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.ENTER) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Input"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('opened again'); - }, - async 'search result_0'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys('Такого точно нету') - .pause(500) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('search result_0'); - }, - async select() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.ARROW_DOWN) - .sendKeys(this.keys.ARROW_DOWN) - .sendKeys(this.keys.ARROW_DOWN) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('select'); - }, - async submit() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - - await delay(1000); - - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.ARROW_DOWN) - .sendKeys(this.keys.ARROW_DOWN) - .sendKeys(this.keys.ARROW_DOWN) - .sendKeys(this.keys.ENTER) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('submit'); - }, - async select_1() { - await delay(1000); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .pause(1000) - .sendKeys('Second') - .pause(500) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .move({ origin: this.browser.findElement({ css: 'body' }) }) - .perform(); - - await delay(1000); - - await this.browser - .actions({ - bridge: true, - }) - .press() - .release() - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('select_1'); - }, - async selected_2() { - await delay(1000); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .pause(1000) - .sendKeys('Second') - .pause(500) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'body' })) - .perform(); - - await delay(1000); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('selected_2'); - }, - }, - }, -}; - export const OpenToTop: Story = () => (
@@ -282,76 +36,6 @@ export const OpenToTop: Story = () => ( ); OpenToTop.storyName = 'open to top'; -OpenToTop.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'hovered' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hovered'] }, - }, - tests: { - async plain() { - const element = await this.browser.findElement({ css: '[data-tid="container"]' }); - await this.expect(await element.takeScreenshot()).to.matchImage('plain'); - }, - async opened() { - const element = await this.browser.findElement({ css: '[data-tid="container"]' }); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - await this.expect(await element.takeScreenshot()).to.matchImage('opened'); - }, - async hovered() { - const element = await this.browser.findElement({ css: '[data-tid="container"]' }); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: '[data-comp-name~="MenuItem"]:nth-of-type(4)' }), - }) - .perform(); - await this.expect(await element.takeScreenshot()).to.matchImage('hovered'); - }, - async selected() { - const element = await this.browser.findElement({ css: '[data-tid="container"]' }); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: '[data-comp-name~="MenuItem"]:nth-of-type(4)' }), - }) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .press() - .release() - .perform(); - await this.expect(await element.takeScreenshot()).to.matchImage('selected'); - }, - }, - }, -}; - export const AlwaysReject: Story = () => (
Promise.reject()} /> @@ -359,22 +43,6 @@ export const AlwaysReject: Story = () => ( ); AlwaysReject.storyName = 'always reject'; -AlwaysReject.parameters = { - creevey: { - tests: { - async opened() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('opened'); - }, - }, - }, -}; - interface SampleState { delay: number; } @@ -515,46 +183,6 @@ WithMaxLength.parameters = { creevey: { skip: true } }; export const ToogleError: Story = () => ; ToogleError.storyName = 'toogle error'; -ToogleError.parameters = { - creevey: { - skip: { - flaky: { in: ['chrome2022', 'chrome2022Dark'], tests: ['plain again', 'with error'] }, - }, - tests: { - async plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('plain'); - }, - async 'with error'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: "[data-comp-name~='Toggle']" })) - .pause(200) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('with error'); - }, - async 'plain again'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: "[data-comp-name~='Toggle']" })) - .pause(200) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: "[data-comp-name~='Toggle']" })) - .pause(200) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('plain again'); - }, - }, - }, -}; - export const WithNullOnUnexpectedInput = () => ( Promise.resolve([])} onUnexpectedInput={() => null} /> ); @@ -564,35 +192,6 @@ WithNullOnUnexpectedInput.parameters = { creevey: { skip: true } }; export const WithExternalValue: Story = () => ; WithExternalValue.storyName = 'with external value'; -WithExternalValue.parameters = { - creevey: { - tests: { - async 'initial value'() { - await this.expect(await this.takeScreenshot()).to.matchImage('initial value'); - }, - async 'reset value'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="resetBtn"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('reset value'); - }, - async 'set value'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="resetBtn"]' })) - .click(this.browser.findElement({ css: '[data-tid="setValueBtn"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('set value'); - }, - }, - }, -}; - export const WithRenderItemState = () => String(state)} />; WithRenderItemState.storyName = 'with renderItem state'; WithRenderItemState.parameters = { creevey: { skip: true } }; @@ -633,40 +232,6 @@ export const FocusFlow: Story = () => ( ); FocusFlow.storyName = 'focus flow'; -FocusFlow.parameters = { - creevey: { - tests: { - async before() { - await this.expect(await this.takeScreenshot()).to.matchImage('before'); - }, - async 'after Enter on Item'() { - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.ENTER) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('after Enter on Item'); - }, - async 'after tab to the next field'() { - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.ENTER) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('after tab to the next field'); - }, - }, - }, -}; - export const NestedComboBoxes = () => { const RecursiveComboboxes = ({ depth }: { depth: number }) => (
@@ -1180,30 +745,6 @@ export const WithTooltip: Story = () => { WithTooltip.storyName = 'with tooltip'; -WithTooltip.parameters = { - creevey: { - tests: { - async 'show and hide Tooltip'() { - const body = await this.browser.findElement({ css: 'body' }); - - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-tid="InputLikeText__input"]' })) - .pause(1000) - .perform(); - - const showTooltip = await body.takeScreenshot(); - - await this.browser.actions({ bridge: true }).click(body).pause(1000).perform(); - - const hideTooltip = await body.takeScreenshot(); - - await this.expect({ showTooltip, hideTooltip }).to.matchImages(); - }, - }, - }, -}; - export const MobileSimple: Story = () => ( <> @@ -1228,19 +769,6 @@ MobileSimple.parameters = { viewport: { defaultViewport: 'iphone', }, - creevey: { - tests: { - async opened() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-tid="ComboBoxView__root"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.browser.takeScreenshot()).to.matchImage('opened'); - }, - }, - }, }; export const WithManualPosition: Story = () => { @@ -1260,65 +788,6 @@ export const WithManualPosition: Story = () => { ); }; WithManualPosition.storyName = 'with manual position'; -WithManualPosition.parameters = { - creevey: { - skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } }, - tests: { - async 'opened top with portal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened top with portal'); - }, - async 'opened bottom with portal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom with portal'); - }, - async 'opened top without portal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="portal"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened top without portal'); - }, - async 'opened bottom without portal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="portal"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-comp-name~="InputLikeText"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom without portal'); - }, - }, - }, -}; export const WithExtendedItem: Story = () => { const [value, setValue] = React.useState(); @@ -1373,7 +842,7 @@ export const WithExtendedItem: Story = () => { } renderItem={(item, state) => } itemWrapper={(item) => - function itemWrapper(props) { + function itemWrapper(props: React.PropsWithChildren) { const isJust2Items = item.id === 5 || item.id === 6; return ; } @@ -1441,26 +910,3 @@ export const Size: Story = () => { }; Size.storyName = 'size'; -Size.parameters = { - creevey: { - tests: { - async 'clicked all'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="open-all"]' })) - .pause(500) - .perform(); - await this.browser.executeScript(function () { - const containers = document.querySelectorAll('[data-tid~="ScrollContainer__inner"]'); - for (let i = 0; i < containers.length; i++) { - containers[i].scrollTop += 300; - } - }); - await delay(1000); - await this.expect(await this.takeScreenshot()).to.matchImage('ClickedAll'); - }, - }, - }, -}; diff --git a/packages/react-ui/components/ComboBox/__tests__/ComboBox-test.tsx b/packages/react-ui/components/ComboBox/__tests__/ComboBox-test.tsx index 9f73fc7d947..ca68f591f36 100644 --- a/packages/react-ui/components/ComboBox/__tests__/ComboBox-test.tsx +++ b/packages/react-ui/components/ComboBox/__tests__/ComboBox-test.tsx @@ -1,8 +1,7 @@ /* eslint-disable jsx-a11y/anchor-has-content */ -/* eslint-disable react/display-name */ /* eslint-disable react/no-unstable-nested-components */ import React, { useState } from 'react'; -import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { MobilePopupDataTids } from '../../../internal/MobilePopup'; @@ -40,6 +39,10 @@ function searchFactory(promise: Promise): [jest.Mock return promise; }); + promise.catch((error) => { + console.error(error); + }); + return [search, searchPromise]; } @@ -56,24 +59,24 @@ describe('ComboBox', () => { expect(() => render( Promise.resolve([])} />)).not.toThrow(); }); - it('focuses on click to input', () => { + it('focuses on click to input', async () => { render( Promise.resolve([])} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); expect(screen.getByRole('textbox')).toHaveFocus(); }); - it('fetches item when focused', () => { + it('fetches item when focused', async () => { const search = jest.fn(() => Promise.resolve([])); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); expect(search).toHaveBeenCalledWith(''); }); - it('fetches items on input', () => { + it('fetches items on input', async () => { const search = jest.fn(() => Promise.resolve([])); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); fireEvent.change(screen.getByRole('textbox'), { target: { value: 'world' } }); expect(search).toHaveBeenCalledTimes(2); @@ -84,7 +87,7 @@ describe('ComboBox', () => { const [search, promise] = searchFactory(Promise.resolve(testValues)); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; expect(screen.queryAllByTestId(ComboBoxMenuDataTids.item)).toHaveLength(testValues.length); @@ -95,7 +98,7 @@ describe('ComboBox', () => { const [search, promise] = searchFactory(Promise.resolve(items)); render( x} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; expect(screen.queryAllByTestId(ComboBoxMenuDataTids.item)).toHaveLength(items.length); @@ -110,7 +113,7 @@ describe('ComboBox', () => { const [search, promise] = searchFactory(Promise.resolve(items)); const onValueChange = jest.fn(); render( x} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; const clickedItemIndex = 0; @@ -126,10 +129,10 @@ describe('ComboBox', () => { const [search, promise] = searchFactory(Promise.resolve(items)); const onValueChange = jest.fn(); render( x} value={'one'} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; - userEvent.type(screen.getByRole('textbox'), '{enter}'); + await userEvent.type(screen.getByRole('textbox'), '{enter}'); expect(onValueChange).toHaveBeenCalledWith('one'); expect(onValueChange).toHaveBeenCalledTimes(1); @@ -139,9 +142,9 @@ describe('ComboBox', () => { const items = ['one', 'two', 'three']; const [search, promise] = searchFactory(Promise.resolve(items)); render( x} value={'one'} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); - userEvent.keyboard('{enter}'); - userEvent.keyboard('{arrowdown}'); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.keyboard('{enter}'); + await userEvent.keyboard('{arrowdown}'); await promise; expect(screen.queryAllByTestId(ComboBoxMenuDataTids.item)).toHaveLength(items.length); @@ -149,13 +152,13 @@ describe('ComboBox', () => { it('retries request on Enter if rejected', async () => { const [search, promise] = searchFactory(Promise.reject()); - render( x} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + render( x.label} />); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; await delay(100); - userEvent.type(screen.getByRole('textbox'), '{enter}'); + await userEvent.type(screen.getByRole('textbox'), '{enter}'); await delay(0); @@ -188,13 +191,13 @@ describe('ComboBox', () => { it('keeps focus after a click on the refresh button', async () => { const [search, promise] = searchFactory(Promise.reject()); - render( x} />); + render( x.label} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; expect(screen.getByTestId(MenuMessageDataTids.root)).toBeInTheDocument(); - userEvent.click(screen.getByTestId(MenuItemDataTids.root)); + await userEvent.click(screen.getByTestId(MenuItemDataTids.root)); await delay(0); expect(search).toHaveBeenCalledTimes(2); @@ -206,10 +209,10 @@ describe('ComboBox', () => { const onUnexpectedInput = jest.fn(); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; - userEvent.type(screen.getByRole('textbox'), 'one'); + await userEvent.type(screen.getByRole('textbox'), 'one'); await promise; @@ -229,25 +232,25 @@ describe('ComboBox', () => { .mockImplementationOnce(() => undefined as unknown as string); render( Promise.resolve([])} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(0); - userEvent.type(screen.getByRole('textbox'), 'one'); + await userEvent.type(screen.getByRole('textbox'), 'one'); clickOutside(); await delay(0); expect(mockFn).toHaveBeenCalledWith('one'); expect(mockFn).toHaveReturnedWith(null); expect(onValueChange).toHaveBeenCalledWith(null); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); - userEvent.type(screen.getByRole('textbox'), 'one'); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.type(screen.getByRole('textbox'), 'one'); await delay(0); clickOutside(); await delay(0); expect(mockFn).toHaveReturnedWith('one'); expect(onValueChange).toHaveBeenCalledWith('one'); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); - userEvent.type(screen.getByRole('textbox'), 'one'); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.type(screen.getByRole('textbox'), 'one'); await delay(0); clickOutside(); await delay(0); @@ -256,11 +259,11 @@ describe('ComboBox', () => { expect(onValueChange).not.toHaveBeenCalledWith(undefined); }); - it('calls onFocus on focus', () => { + it('calls onFocus on focus', async () => { const onFocus = jest.fn(); render( Promise.resolve([])} />); - userEvent.tab(); + await userEvent.tab(); expect(onFocus).toHaveBeenCalledTimes(1); }); @@ -275,7 +278,7 @@ describe('ComboBox', () => { }); it('calls onBlur on click outside when menu is open', async () => { - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; expect(screen.getByTestId(ComboBoxMenuDataTids.item)).toBeInTheDocument(); @@ -287,9 +290,10 @@ describe('ComboBox', () => { }); it('calls onBlur on input blur when menu is closed', async () => { - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); - userEvent.type(screen.getByRole('textbox'), '{esc}'); - + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + act(() => { + fireEvent.keyDown(screen.getByRole('textbox'), { key: 'Escape', code: 'Escape' }); + }); expect(screen.queryByTestId(MenuDataTids.root)).not.toBeInTheDocument(); fireEvent.blur(screen.getByRole('textbox')); @@ -305,7 +309,7 @@ describe('ComboBox', () => { const [search, promise] = searchFactory(Promise.resolve(items)); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; expect(screen.getByTestId(MenuDataTids.root)).toBeInTheDocument(); @@ -322,10 +326,10 @@ describe('ComboBox', () => { const onValueChange = jest.fn(); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; - userEvent.click(screen.getByText('Hello, world')); + await userEvent.click(screen.getByText('Hello, world')); expect(onValueChange).toHaveBeenCalledTimes(1); expect(onValueChange).toHaveBeenCalledWith({ id: 'hello', @@ -345,10 +349,10 @@ describe('ComboBox', () => { render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; - userEvent.click(screen.getByText('Hello, world')); + await userEvent.click(screen.getByText('Hello, world')); expect(onClick).toHaveBeenCalledTimes(1); }); @@ -357,7 +361,7 @@ describe('ComboBox', () => { const [search, promise] = searchFactory(Promise.resolve([])); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; const input = screen.getByRole('textbox'); @@ -375,12 +379,12 @@ describe('ComboBox', () => { it('clear input value if onUnexpectedInput return null', async () => { render( null} getItems={() => Promise.resolve([])} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); fireEvent.change(screen.getByRole('textbox'), { target: { value: 'foo' } }); - - clickOutside(); - await delay(0); + act(() => { + clickOutside(); + }); expect(screen.getByRole('textbox')).toHaveTextContent(''); }); @@ -389,7 +393,7 @@ describe('ComboBox', () => { const [search] = searchFactory(delay(500).then(() => [])); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(300); expect(screen.getByTestId(SpinnerDataTids.root)).toBeInTheDocument(); @@ -412,7 +416,7 @@ describe('ComboBox', () => { const [search, promise] = searchFactory(Promise.resolve(items)); render( x} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; const menuItems = screen.getAllByTestId(ComboBoxMenuDataTids.item); @@ -424,7 +428,7 @@ describe('ComboBox', () => { const [search, promise] = searchFactory(Promise.resolve(items)); render( x} value={'one'} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; const menuItems = screen.getAllByTestId(ComboBoxMenuDataTids.item); @@ -466,22 +470,22 @@ describe('ComboBox', () => { describe('keep edited input text when value changes', () => { const value = { value: 1, label: 'one' }; - it('in default mode', () => { + it('in default mode', async () => { const { rerender } = render( Promise.resolve([value])} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); fireEvent.change(screen.getByRole('textbox'), { target: { value: 'two' } }); clickOutside(); rerender( Promise.resolve([value])} />); - userEvent.click(screen.getByRole('textbox')); + await userEvent.click(screen.getByRole('textbox')); expect(screen.getByRole('textbox')).toHaveValue('two'); }); - it('in autocomplete mode', () => { + it('in autocomplete mode', async () => { const { rerender } = render( Promise.resolve([value])} />, ); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); fireEvent.change(screen.getByRole('textbox'), { target: { value: 'two' } }); clickOutside(); @@ -489,7 +493,7 @@ describe('ComboBox', () => { Promise.resolve([value])} />, ); - userEvent.click(screen.getByRole('textbox')); + await userEvent.click(screen.getByRole('textbox')); expect(screen.getByRole('textbox')).toHaveValue('two'); }); }); @@ -499,17 +503,17 @@ describe('ComboBox', () => { const getItems = jest.fn(); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(0); expect(getItems).toHaveBeenCalledTimes(0); expect(screen.queryByTestId(ComboBoxMenuDataTids.items)).not.toBeInTheDocument(); }); - it('reset', () => { + it('reset', async () => { render( Promise.resolve([])} ref={comboboxRef} />); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); fireEvent.change(screen.getByRole('textbox'), { target: { value: 'foo' } }); expect(screen.getByRole('textbox')).toHaveValue('foo'); @@ -532,7 +536,7 @@ describe('ComboBox', () => { const changeHandler = jest.fn(); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); fireEvent.change(screen.getByRole('textbox'), { target: { value: testValues[1].label } }); @@ -613,14 +617,14 @@ describe('ComboBox', () => { beforeEach(async () => { render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); delay(0); onFocus.mockClear(); onBlur.mockClear(); }); it('click on item', async () => { - userEvent.click(screen.getAllByTestId(ComboBoxMenuDataTids.item)[0]); + await userEvent.click(screen.getAllByTestId(ComboBoxMenuDataTids.item)[0]); await delay(0); // await for restore focus expect(screen.getByRole('textbox')).toHaveFocus(); @@ -635,8 +639,8 @@ describe('ComboBox', () => { }); it('Enter on item', async () => { - userEvent.keyboard('{arrowdown}'); - userEvent.keyboard('{enter}'); + await userEvent.keyboard('{arrowdown}'); + await userEvent.keyboard('{enter}'); await delay(0); @@ -658,7 +662,7 @@ describe('ComboBox', () => { describe('in default mode', () => { beforeEach(async () => { render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); getItems.mockClear(); }); @@ -667,50 +671,50 @@ describe('ComboBox', () => { expect(screen.queryByTestId(MenuDataTids.root)).not.toBeInTheDocument(); - userEvent.click(screen.getByRole('textbox')); + await userEvent.click(screen.getByRole('textbox')); await delay(0); expect(screen.getByTestId(MenuDataTids.root)).toBeInTheDocument(); expect(screen.getAllByTestId(ComboBoxMenuDataTids.item)).toHaveLength(testValues.length); }); - it('runs empty search if menu is closed', () => { + it('runs empty search if menu is closed', async () => { comboboxRef.current?.close(); delay(0); expect(screen.queryByTestId(MenuDataTids.root)).not.toBeInTheDocument(); - userEvent.click(screen.getByRole('textbox')); + await userEvent.click(screen.getByRole('textbox')); expect(getItems).toHaveBeenCalledWith(''); }); - it("doesn't run search if menu is open", () => { - userEvent.click(screen.getByRole('textbox')); + it("doesn't run search if menu is open", async () => { + await userEvent.click(screen.getByRole('textbox')); expect(getItems).toHaveBeenCalledTimes(0); }); }); describe('in autocomplete mode', () => { - beforeEach(() => { + beforeEach(async () => { render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); getItems.mockClear(); }); - it("doesn't open menu if it is closed", () => { + it("doesn't open menu if it is closed", async () => { comboboxRef.current?.close(); - userEvent.click(screen.getByRole('textbox')); + await userEvent.click(screen.getByRole('textbox')); expect(screen.queryByTestId(MenuDataTids.root)).not.toBeInTheDocument(); }); - it("doesn't run search if menu is closed", () => { + it("doesn't run search if menu is closed", async () => { comboboxRef.current?.close(); - userEvent.click(screen.getByRole('textbox')); + await userEvent.click(screen.getByRole('textbox')); expect(getItems).toHaveBeenCalledTimes(0); }); - it("doesn't run search if menu is open", () => { - userEvent.click(screen.getByRole('textbox')); + it("doesn't run search if menu is open", async () => { + await userEvent.click(screen.getByRole('textbox')); expect(getItems).toHaveBeenCalledTimes(0); }); }); @@ -997,7 +1001,7 @@ describe('ComboBox', () => { }); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(300); expect(screen.getByTestId(SpinnerDataTids.root)).toBeInTheDocument(); @@ -1006,7 +1010,7 @@ describe('ComboBox', () => { expect(screen.queryByTestId(SpinnerDataTids.root)).not.toBeInTheDocument(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(300); expect(screen.getByTestId(SpinnerDataTids.root)).toBeInTheDocument(); @@ -1019,7 +1023,7 @@ describe('ComboBox', () => { }); render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(600); expect(screen.getByTestId(SpinnerDataTids.root)).toBeInTheDocument(); @@ -1029,7 +1033,7 @@ describe('ComboBox', () => { expect(screen.queryByTestId(SpinnerDataTids.root)).not.toBeInTheDocument(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(300); expect(screen.getByTestId(SpinnerDataTids.root)).toBeInTheDocument(); @@ -1043,7 +1047,7 @@ describe('ComboBox', () => { [search, promise] = searchFactory(Promise.resolve(null)); }); const focus = async (): Promise => { - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await promise; }; @@ -1116,7 +1120,7 @@ describe('ComboBox', () => { }); }); - it.each(['', null, undefined])('should clear the value when %s passed', (testValue) => { + it.each(['', null, undefined])('should clear the value when %s passed', async (testValue) => { const Comp = () => { const [value, setValue] = useState({ value: 1, label: 'First' }); @@ -1137,7 +1141,7 @@ describe('ComboBox', () => { const input = screen.getByTestId('InputLikeText__input'); expect(input).toHaveTextContent(/^First$/); - userEvent.click(screen.getByRole('button', { name: 'Clear' })); + await userEvent.click(screen.getByRole('button', { name: 'Clear' })); expect(input).toHaveTextContent(''); }); @@ -1200,10 +1204,11 @@ describe('ComboBox', () => { const addNewElement = async () => { render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); - userEvent.type(screen.getByRole('textbox'), 'newItem'); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.clear(screen.getByRole('textbox')); + await userEvent.type(screen.getByRole('textbox'), 'newItem'); await delay(0); - userEvent.click(screen.getByTestId('addButton')); + await userEvent.click(screen.getByTestId('addButton')); }; it('add new element', async () => { @@ -1213,13 +1218,13 @@ describe('ComboBox', () => { it('show added item after blur', async () => { await addNewElement(); - userEvent.click(screen.getByRole('textbox')); + await userEvent.click(screen.getByRole('textbox')); await delay(0); expect(screen.getAllByTestId(ComboBoxMenuDataTids.item)).toHaveLength(4); clickOutside(); await delay(0); expect(screen.queryByTestId(ComboBoxMenuDataTids.item)).not.toBeInTheDocument(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(0); expect(screen.getAllByTestId(ComboBoxMenuDataTids.item)).toHaveLength(4); }); @@ -1232,7 +1237,7 @@ describe('ComboBox', () => { { value: 2, label: 'Second' }, ]; - const itemWrapper = (item?: { value: number; label: string }) => { + const itemWrapper = (item: { value: number; label: string }) => { if (item?.value === 2) { return (props: HTMLProps['a']) => ; } @@ -1247,7 +1252,7 @@ describe('ComboBox', () => { render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(0); expect(screen.getByRole('button', { name: 'First' })).toBeInTheDocument(); expect(screen.getByRole('link', { name: 'Second' })).toBeInTheDocument(); @@ -1296,7 +1301,7 @@ describe('ComboBox', () => { expect.stringContaining(ComboBoxViewIds.menu), ); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); expect(screen.getByTestId(InputDataTids.root)).toHaveAttribute( 'aria-controls', @@ -1311,11 +1316,11 @@ describe('ComboBox', () => { }); }); - it('sets value for aria-label attribute', () => { + it('sets value for aria-label attribute', async () => { const ariaLabel = 'aria-label'; render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); expect(screen.getByRole('textbox')).toHaveAttribute('aria-label', ariaLabel); }); @@ -1371,10 +1376,10 @@ describe('ComboBox', () => { render(); comboboxRef.current?.focus(); expect(screen.getByRole('textbox')).toHaveValue(initialValue.label); - userEvent.clear(screen.getByRole('textbox')); + await userEvent.clear(screen.getByRole('textbox')); expect(await screen.findByRole('textbox')).toHaveValue(''); - userEvent.click(screen.getByRole('button', { name: 'Обновить' })); + await userEvent.click(screen.getByRole('button', { name: 'Обновить' })); expect(await screen.findByRole('textbox')).toHaveValue(expectedValue.label); }); @@ -1434,7 +1439,7 @@ describe('mobile comboBox', () => { it('should fully close by method', async () => { render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(500); close(); @@ -1444,12 +1449,12 @@ describe('mobile comboBox', () => { it('should close and open again after being closed by public method', async () => { render(); - userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); + await userEvent.click(screen.getByTestId(InputLikeTextDataTids.root)); await delay(500); close(); - userEvent.click(screen.getByTestId(InputDataTids.root)); + await userEvent.click(screen.getByTestId(InputDataTids.root)); await delay(500); expect(screen.getByTestId(MobilePopupDataTids.root)).toBeInTheDocument(); diff --git a/packages/react-ui/components/CurrencyInput/CurrencyInput.tsx b/packages/react-ui/components/CurrencyInput/CurrencyInput.tsx index df427a42744..40ea75e47ed 100644 --- a/packages/react-ui/components/CurrencyInput/CurrencyInput.tsx +++ b/packages/react-ui/components/CurrencyInput/CurrencyInput.tsx @@ -1,5 +1,3 @@ -// TODO: Enable this rule in functional components. -/* eslint-disable @typescript-eslint/no-unused-vars */ import React, { AriaAttributes } from 'react'; import PropTypes from 'prop-types'; import warning from 'warning'; @@ -156,7 +154,7 @@ export class CurrencyInput extends React.PureComponent + {this.renderMain} ); diff --git a/packages/react-ui/components/CurrencyInput/__creevey__/CurrencyInput.creevey.ts b/packages/react-ui/components/CurrencyInput/__creevey__/CurrencyInput.creevey.ts new file mode 100644 index 00000000000..c530da2a156 --- /dev/null +++ b/packages/react-ui/components/CurrencyInput/__creevey__/CurrencyInput.creevey.ts @@ -0,0 +1,77 @@ +import { story, kind, test } from 'creevey'; + +kind('CurrencyInput', () => { + story('SampleStory', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'flacky visible(?!) cursor': { + in: ['chromeDark'], + tests: ['Focus', 'Input value', 'External focus and input'], + }, + }, + }); + + test('Plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); + }); + + test('Focus', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click( + this.browser.findElement({ + css: '[data-comp-name*="CurrencyInput"] input', + }), + ) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('Focus'); + }); + + test('Input value', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click( + this.browser.findElement({ + css: '[data-comp-name*="CurrencyInput"] input', + }), + ) + .sendKeys('1') + .pause(500) + .sendKeys('2') + .pause(500) + .sendKeys('3') + .pause(500) + .sendKeys('4') + .pause(500) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('Input value'); + }); + + test('External focus and input', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="focus-input"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('1') + .pause(500) + .sendKeys('2') + .pause(500) + .sendKeys('3') + .pause(500) + .sendKeys('4') + .pause(500) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('External focus and input'); + }); + }); +}); diff --git a/packages/react-ui/components/CurrencyInput/__stories__/CurrencyInput.stories.tsx b/packages/react-ui/components/CurrencyInput/__stories__/CurrencyInput.stories.tsx index 80b240b034f..fbe1956b2e2 100644 --- a/packages/react-ui/components/CurrencyInput/__stories__/CurrencyInput.stories.tsx +++ b/packages/react-ui/components/CurrencyInput/__stories__/CurrencyInput.stories.tsx @@ -14,8 +14,6 @@ interface CurrencyInputDemoProps { borderless?: boolean; } interface CurrencyInputDemoState { - // Intended behavior. CurrencyInput technically can't accept strings - // eslint-disable-next-line @typescript-eslint/no-explicit-any value: any; hideTrailingZeros: boolean; fractionDigits: number; @@ -169,70 +167,6 @@ WithBorderless.parameters = { creevey: { skip: true } }; export const SampleStory: Story = () => ; SampleStory.storyName = 'Sample'; -SampleStory.parameters = { - creevey: { - skip: { - 'flacky visible(?!) cursor': { - in: ['chromeDark'], - tests: ['Focus', 'Input value', 'External focus and input'], - }, - }, - tests: { - async Plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); - }, - async Focus() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name*="CurrencyInput"] input' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('Focus'); - }, - async 'Input value'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name*="CurrencyInput"] input' })) - .sendKeys('1') - .pause(500) - .sendKeys('2') - .pause(500) - .sendKeys('3') - .pause(500) - .sendKeys('4') - .pause(500) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('Input value'); - }, - async 'External focus and input'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="focus-input"]' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys('1') - .pause(500) - .sendKeys('2') - .pause(500) - .sendKeys('3') - .pause(500) - .sendKeys('4') - .pause(500) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('External focus and input'); - }, - }, - }, -}; - export const ManualMount = () => { class ManualMounting extends React.Component { public state = { diff --git a/packages/react-ui/components/CurrencyInput/__tests__/CurrencyInput-test.tsx b/packages/react-ui/components/CurrencyInput/__tests__/CurrencyInput-test.tsx index d58fa794d0b..c7bd4454dd6 100644 --- a/packages/react-ui/components/CurrencyInput/__tests__/CurrencyInput-test.tsx +++ b/packages/react-ui/components/CurrencyInput/__tests__/CurrencyInput-test.tsx @@ -1,12 +1,10 @@ import React, { useState } from 'react'; -import { fireEvent, render, screen } from '@testing-library/react'; +import { act, fireEvent, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { CurrencyInput } from '../CurrencyInput'; import { Nullable } from '../../../typings/utility-types'; -// Intended behavior. CurrencyInput technically can't accept strings -// eslint-disable-next-line @typescript-eslint/no-explicit-any const CurrencyInputWithValueProp = (props: { value: any }): JSX.Element => { const handleValueChange = jest.fn(); return ; @@ -18,8 +16,6 @@ const CurrencyInputWithState = () => { }; const CurrencyInputAndButton = (props: { value: unknown }): JSX.Element => { - // Intended behavior. CurrencyInput technically can't accept strings - // eslint-disable-next-line @typescript-eslint/no-explicit-any const [value, setValue] = useState>(12); return (
@@ -29,6 +25,12 @@ const CurrencyInputAndButton = (props: { value: unknown }): JSX.Element => { ); }; +const clearInput = async (input: Element) => { + for (let i = 0; i < 5; i++) { + await userEvent.type(input, '{backspace}'); + } +}; + describe('CurrencyInput', () => { it('should mount with a number value', () => { render(); @@ -59,36 +61,41 @@ describe('CurrencyInput', () => { expect(input).toHaveValue(''); }); - it('should set a correct number value', () => { + it('should set a correct number value', async () => { render(); const input = screen.getByRole('textbox'); - userEvent.clear(input); - userEvent.type(input, '123'); - input.blur(); + await clearInput(input); + await userEvent.type(input, '123'); + act(() => { + input.blur(); + }); expect(input).toHaveValue('123,00'); }); - it('should not set a string value', () => { + it('should not set a string value', async () => { render(); const input = screen.getByRole('textbox'); - userEvent.clear(input); - userEvent.type(input, 'str'); - input.blur(); + await clearInput(input); + await userEvent.type(input, 'str'); + act(() => { + input.blur(); + }); expect(input).toHaveValue(''); }); - it('should change value with a valid number', () => { + it('should change value with a valid number', async () => { render(); const button = screen.getByRole('button'); - userEvent.click(button); + await userEvent.click(button); const input = screen.getByRole('textbox'); expect(input).toHaveValue('123,00'); }); - it('should change value and not throw an error with a valid string', () => { - render(); + it('should change value and not throw an error with a valid string', async () => { + render(); const button = screen.getByRole('button'); expect(() => userEvent.click(button)).not.toThrow(); + await userEvent.click(button); const input = screen.getByRole('textbox'); expect(input).toHaveValue('123,00'); }); @@ -109,7 +116,7 @@ describe('CurrencyInput', () => { expect(input).toHaveValue('12,00'); }); - it('should clear `value` in input when undefined passed', () => { + it('should clear `value` in input when undefined passed', async () => { const Comp = () => { const [value, setValue] = useState>(12345); return ( @@ -121,11 +128,11 @@ describe('CurrencyInput', () => { }; render(); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(screen.getByRole('textbox')).toHaveValue(''); }); - it('should clear `value` in input when null passed', () => { + it('should clear `value` in input when null passed', async () => { const Comp = () => { const [value, setValue] = useState>(12345); return ( @@ -137,7 +144,7 @@ describe('CurrencyInput', () => { }; render(); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(screen.getByRole('textbox')).toHaveValue(''); }); @@ -149,7 +156,9 @@ describe('CurrencyInput', () => { }; render(); - currencyInputRef.current?.focus(); + act(() => { + currencyInputRef.current?.focus(); + }); expect(screen.getByRole('textbox')).toHaveFocus(); }); @@ -161,7 +170,9 @@ describe('CurrencyInput', () => { return ; }; render(); - currencyInputRef.current?.focus(); + act(() => { + currencyInputRef.current?.focus(); + }); expect(screen.getByRole('textbox')).toHaveFocus(); expect(onFocus).toHaveBeenCalled(); }); @@ -173,9 +184,13 @@ describe('CurrencyInput', () => { return ; }; render(); - screen.getByRole('textbox').focus(); + act(() => { + screen.getByRole('textbox').focus(); + }); expect(screen.getByRole('textbox')).toHaveFocus(); - currencyInputRef.current?.blur(); + act(() => { + currencyInputRef.current?.blur(); + }); expect(screen.getByRole('textbox')).not.toHaveFocus(); }); @@ -189,19 +204,21 @@ describe('CurrencyInput', () => { render(); screen.getByRole('textbox').focus(); expect(screen.getByRole('textbox')).toHaveFocus(); - currencyInputRef.current?.blur(); + act(() => { + currencyInputRef.current?.blur(); + }); expect(screen.getByRole('textbox')).not.toHaveFocus(); expect(onBlur).toHaveBeenCalled(); }); - it('should handle onKeyDown event', () => { + it('should handle onKeyDown event', async () => { const onKeyDown = jest.fn(); const Comp = () => { const [value, setValue] = useState>(12345); return ; }; render(); - userEvent.type(screen.getByRole('textbox'), '{enter}'); + await userEvent.type(screen.getByRole('textbox'), '{enter}'); expect(onKeyDown).toHaveBeenCalledTimes(1); }); @@ -212,7 +229,7 @@ describe('CurrencyInput', () => { return ; }; - it('should handle cursor Backspace move key down correctly', () => { + it('should handle cursor Backspace move key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 4; @@ -220,15 +237,15 @@ describe('CurrencyInput', () => { fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - userEvent.keyboard('{backspace}'); - userEvent.keyboard('{backspace}'); + await userEvent.keyboard('{backspace}'); + await userEvent.keyboard('{backspace}'); //should be on 1 position due to the automatic ⎵ between 12 and 300 expect(input.selectionStart).toBe(1); expect(input.selectionEnd).toBe(1); }); - it('should handle cursor right move key down correctly', () => { + it('should handle cursor right move key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 0; @@ -236,15 +253,15 @@ describe('CurrencyInput', () => { fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - userEvent.keyboard('{arrowright}'); - userEvent.keyboard('{arrowright}'); + await userEvent.keyboard('{arrowright}'); + await userEvent.keyboard('{arrowright}'); //should be on 3 position due to the automatic ⎵ between 12 and 300 expect(input.selectionStart).toBe(3); expect(input.selectionEnd).toBe(3); }); - it('should handle cursor left move key down correctly', () => { + it('should handle cursor left move key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 4; @@ -252,15 +269,15 @@ describe('CurrencyInput', () => { fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - userEvent.keyboard('{arrowleft}'); - userEvent.keyboard('{arrowleft}'); + await userEvent.keyboard('{arrowleft}'); + await userEvent.keyboard('{arrowleft}'); //should be on 1 position due to the automatic ⎵ between 12 and 300 expect(input.selectionStart).toBe(1); expect(input.selectionEnd).toBe(1); }); - it('should handle move to start key down correctly', () => { + it('should handle move to start key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 4; @@ -268,13 +285,13 @@ describe('CurrencyInput', () => { fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - userEvent.keyboard('{home}'); + await userEvent.keyboard('{home}'); expect(input.selectionStart).toBe(0); expect(input.selectionEnd).toBe(0); }); - it('should handle move to end key down correctly', () => { + it('should handle move to end key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 4; @@ -282,28 +299,27 @@ describe('CurrencyInput', () => { fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - userEvent.keyboard('{end}'); + fireEvent.keyDown(input, { key: 'End', code: 'End' }); expect(input.selectionStart).toBe(input.value?.length); expect(input.selectionEnd).toBe(input.value?.length); }); - it('should handle selection left extension key down correctly', () => { + it('should handle selection left extension key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 4; - fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - - userEvent.keyboard('{shift}{arrowleft/}{arrowleft/}{/shift}'); + fireEvent.keyDown(input, { key: 'ArrowLeft', code: 'ArrowLeft', shiftKey: true }); + fireEvent.keyDown(input, { key: 'ArrowLeft', code: 'ArrowLeft', shiftKey: true }); //should be selected from 1 position due to the automatic ⎵ between 12 and 300 expect(input.selectionStart).toBe(1); expect(input.selectionEnd).toBe(startCursorPosition); }); - it('should handle selection right extension key down correctly', () => { + it('should handle selection right extension key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 0; @@ -311,14 +327,14 @@ describe('CurrencyInput', () => { fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - userEvent.keyboard('{shift}{arrowright/}{arrowright/}{/shift}'); - + fireEvent.keyDown(input, { key: 'ArrowRight', code: 'ArrowRight', shiftKey: true }); + fireEvent.keyDown(input, { key: 'ArrowRight', code: 'ArrowRight', shiftKey: true }); //should be selected till 3 position due to the automatic ⎵ between 12 and 300 expect(input.selectionStart).toBe(startCursorPosition); expect(input.selectionEnd).toBe(3); }); - it('should handle full selection key down correctly', () => { + it('should handle full selection key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 0; @@ -326,13 +342,13 @@ describe('CurrencyInput', () => { fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - userEvent.keyboard('{ctrl}a{/ctrl}'); + fireEvent.keyDown(input, { key: 'a', code: 'KeyA', ctrlKey: true }); expect(input.selectionStart).toBe(startCursorPosition); expect(input.selectionEnd).toBe(input.value?.length); }); - it('should handle selection to start key down correctly', () => { + it('should handle selection to start key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 4; @@ -340,13 +356,13 @@ describe('CurrencyInput', () => { fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - userEvent.keyboard('{shift}{home/}{/shift}'); + fireEvent.keyDown(input, { key: 'Home', code: 'Home', shiftKey: true }); expect(input.selectionStart).toBe(0); expect(input.selectionEnd).toBe(startCursorPosition); }); - it('should handle selection to end key down correctly', () => { + it('should handle selection to end key down correctly', async () => { render(); const input = screen.getByRole('textbox') as HTMLInputElement; const startCursorPosition = 4; @@ -354,7 +370,7 @@ describe('CurrencyInput', () => { fireEvent.focus(input); input.setSelectionRange(startCursorPosition, startCursorPosition); - userEvent.keyboard('{shift}{end/}{/shift}'); + fireEvent.keyDown(input, { key: 'End', code: 'End', shiftKey: true }); expect(input.selectionStart).toBe(startCursorPosition); expect(input.selectionEnd).toBe(input.value?.length); @@ -369,12 +385,14 @@ describe('CurrencyInput', () => { ['IntlBackslash', '1,23'], ['NumpadDivide', '1,23'], ])('should applied [%s] as comma', (delimiter, expected) => { - it(`return: ${expected}`, () => { + it(`return: ${expected}`, async () => { render(); const input = screen.getByRole('textbox'); - userEvent.clear(input); - userEvent.keyboard(`1[${delimiter}]23`, {}); - input.blur(); + await clearInput(input); + await userEvent.keyboard(`1[${delimiter}]23`, {}); + act(() => { + input.blur(); + }); expect(input).toHaveValue(expected); }); }); diff --git a/packages/react-ui/components/CurrencyLabel/__tests__/CurrencyLabel-test.tsx b/packages/react-ui/components/CurrencyLabel/__tests__/CurrencyLabel-test.tsx index 839c02f922a..52f6f39ba0d 100644 --- a/packages/react-ui/components/CurrencyLabel/__tests__/CurrencyLabel-test.tsx +++ b/packages/react-ui/components/CurrencyLabel/__tests__/CurrencyLabel-test.tsx @@ -37,7 +37,6 @@ describe('CurrencyLabel', () => { }); describe('Warnings', () => { - // eslint-disable-next-line @typescript-eslint/no-empty-function const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); afterEach(() => { diff --git a/packages/react-ui/components/DateInput/CalendarIcon.tsx b/packages/react-ui/components/DateInput/CalendarIcon.tsx index 1acb5e73bc4..6ca08d59228 100644 --- a/packages/react-ui/components/DateInput/CalendarIcon.tsx +++ b/packages/react-ui/components/DateInput/CalendarIcon.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/display-name */ import React from 'react'; import { CalendarIcon16Light } from '../../internal/icons2022/CalendarIcon/CalendarIcon16Light'; diff --git a/packages/react-ui/components/DateInput/__creevey__/DateInput.creevey.ts b/packages/react-ui/components/DateInput/__creevey__/DateInput.creevey.ts new file mode 100644 index 00000000000..98bf3d9bf53 --- /dev/null +++ b/packages/react-ui/components/DateInput/__creevey__/DateInput.creevey.ts @@ -0,0 +1,155 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('DateInput', () => { + story('Simple', () => { + test('idle', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('idle'); + }); + + test('focus', async function () { + await this.browser.executeScript(function () { + const input = window.document.querySelector("[data-comp-name~='DateInput']"); + if (input instanceof HTMLElement) { + input.focus(); + } + }); + await this.expect(await this.takeScreenshot()).to.matchImage('focus'); + }); + }); + + story('Disabled', () => { + test('idle', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('idle'); + }); + + test('focus', async function () { + await this.browser.executeScript(function () { + const input = window.document.querySelector("[data-comp-name~='DateInput']"); + if (input instanceof HTMLElement) { + input.focus(); + } + }); + await this.expect(await this.takeScreenshot()).to.matchImage('focus'); + }); + }); + + story('WithWidth', () => { + test('idle', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('idle'); + }); + + test('focus', async function () { + await this.browser.executeScript(function () { + const input = window.document.querySelector("[data-comp-name~='DateInput']"); + if (input instanceof HTMLElement) { + input.focus(); + } + }); + await this.expect(await this.takeScreenshot()).to.matchImage('focus'); + }); + }); + + story('BlurAlwaysAfterChange', () => { + test('value not changed', async function () { + await this.browser.executeScript(function () { + const input = window.document.querySelector("[data-comp-name~='DateInput']"); + if (input instanceof HTMLElement) { + input.focus(); + } + }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'body' })) + .perform(); + await delay(500); + await this.expect(await this.takeScreenshot()).to.matchImage('value not changed'); + }); + + test('value changed', async function () { + await this.browser.executeScript(function () { + const input = window.document.querySelector("[data-comp-name~='DateInput']"); + if (input instanceof HTMLElement) { + input.focus(); + } + }); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys('12') + .click(this.browser.findElement({ css: 'body' })) + .perform(); + await delay(500); + await this.expect(await this.takeScreenshot()).to.matchImage('value changed'); + }); + + test('value restored', async function () { + await this.browser.executeScript(function () { + const input = window.document.querySelector("[data-comp-name~='DateInput']"); + if (input instanceof HTMLElement) { + input.focus(); + } + }); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.NUMPAD1) + .click(this.browser.findElement({ css: 'body' })) + .perform(); + await this.browser.executeScript(function () { + const input = window.document.querySelector("[data-comp-name~='DateInput']"); + if (input instanceof HTMLElement) { + input.blur(); + } + }); + await this.expect(await this.takeScreenshot()).to.matchImage('value restored'); + }); + }); + + story('WithNoValue', () => { + test('idle', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage(); + }); + + test('focused', async function () { + await this.browser.executeScript(function () { + const input = window.document.querySelector("[data-comp-name~='DateInput']"); + if (input instanceof HTMLElement) { + input.focus(); + } + }); + await this.expect(await this.takeScreenshot()).to.matchImage(); + }); + }); + + story('WithError', () => { + test('focused', async function () { + const plain = await this.takeScreenshot(); + const DateInputPlaceholder = this.browser.findElement({ + css: '[data-tid~="DateFragmentsView__placeholder"]', + }); + await this.browser.actions({ bridge: true }).click(DateInputPlaceholder).perform(); + await delay(1000); + const focused = await this.takeScreenshot(); + await this.expect([plain, focused]).to.matchImages(); + }); + }); + + story('ShouldSetFocusOnPlaceholderClick', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'chrome only': { in: /^(?!\bchrome\b)/ } } }); + + test('focused', async function () { + const DateInputPlaceholder = this.browser.findElement({ + css: '[data-tid~="DateFragmentsView__placeholder"]', + }); + await this.browser.actions({ bridge: true }).click(DateInputPlaceholder).perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage(); + }); + }); +}); diff --git a/packages/react-ui/components/DateInput/__stories__/DateInput.stories.tsx b/packages/react-ui/components/DateInput/__stories__/DateInput.stories.tsx index c1fb5aacb71..b428e38c7ba 100644 --- a/packages/react-ui/components/DateInput/__stories__/DateInput.stories.tsx +++ b/packages/react-ui/components/DateInput/__stories__/DateInput.stories.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { action } from '@storybook/addon-actions'; -import { delay } from '../../../lib/utils'; import { Meta, Story } from '../../../typings/stories'; import { InternalDateOrder, InternalDateSeparator } from '../../../lib/date/types'; import { Gapped } from '../../Gapped'; @@ -282,25 +281,6 @@ export default { title: 'DateInput' } as Meta; export const Simple: Story = () => ; Simple.storyName = 'simple'; -Simple.parameters = { - creevey: { - tests: { - async idle() { - await this.expect(await this.takeScreenshot()).to.matchImage('idle'); - }, - async focus() { - await this.browser.executeScript(function () { - const input = window.document.querySelector("[data-comp-name~='DateInput']"); - if (input instanceof HTMLElement) { - input.focus(); - } - }); - await this.expect(await this.takeScreenshot()).to.matchImage('focus'); - }, - }, - }, -}; - export const WithAutoFocus: Story = () => ; WithAutoFocus.storyName = 'with autoFocus'; @@ -314,131 +294,13 @@ DifferentFormatting.storyName = 'different formatting'; export const Disabled: Story = () => ; Disabled.storyName = 'disabled'; -Disabled.parameters = { - creevey: { - tests: { - async idle() { - await this.expect(await this.takeScreenshot()).to.matchImage('idle'); - }, - async focus() { - await this.browser.executeScript(function () { - const input = window.document.querySelector("[data-comp-name~='DateInput']"); - if (input instanceof HTMLElement) { - input.focus(); - } - }); - await this.expect(await this.takeScreenshot()).to.matchImage('focus'); - }, - }, - }, -}; - export const WithWidth: Story = () => ; WithWidth.storyName = 'with width'; -WithWidth.parameters = { - creevey: { - tests: { - async idle() { - await this.expect(await this.takeScreenshot()).to.matchImage('idle'); - }, - async focus() { - await this.browser.executeScript(function () { - const input = window.document.querySelector("[data-comp-name~='DateInput']"); - if (input instanceof HTMLElement) { - input.focus(); - } - }); - await this.expect(await this.takeScreenshot()).to.matchImage('focus'); - }, - }, - }, -}; - export const BlurAlwaysAfterChange: Story = () => ; BlurAlwaysAfterChange.storyName = 'blur always after change'; -BlurAlwaysAfterChange.parameters = { - creevey: { - tests: { - async 'value not changed'() { - await this.browser.executeScript(function () { - const input = window.document.querySelector("[data-comp-name~='DateInput']"); - if (input instanceof HTMLElement) { - input.focus(); - } - }); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'body' })) - .pause(500) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('value not changed'); - }, - async 'value changed'() { - await this.browser.executeScript(function () { - const input = window.document.querySelector("[data-comp-name~='DateInput']"); - if (input instanceof HTMLElement) { - input.focus(); - } - }); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys('12') - .click(this.browser.findElement({ css: 'body' })) - .pause(500) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('value changed'); - }, - async 'value restored'() { - await this.browser.executeScript(function () { - const input = window.document.querySelector("[data-comp-name~='DateInput']"); - if (input instanceof HTMLElement) { - input.focus(); - } - }); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.DELETE) - .click(this.browser.findElement({ css: 'body' })) - .perform(); - await this.browser.executeScript(function () { - const input = window.document.querySelector("[data-comp-name~='DateInput']"); - if (input instanceof HTMLElement) { - input.blur(); - } - }); - await this.expect(await this.takeScreenshot()).to.matchImage('value restored'); - }, - }, - }, -}; - export const WithNoValue: Story = () => ; -WithNoValue.parameters = { - creevey: { - tests: { - async idle() { - await this.expect(await this.takeScreenshot()).to.matchImage(); - }, - async focused() { - await this.browser.executeScript(function () { - const input = window.document.querySelector("[data-comp-name~='DateInput']"); - if (input instanceof HTMLElement) { - input.focus(); - } - }); - await this.expect(await this.takeScreenshot()).to.matchImage(); - }, - }, - }, -}; export const WithError: Story = () => ( @@ -451,39 +313,7 @@ export const WithError: Story = () => ( ); -WithError.parameters = { - creevey: { - tests: { - async focused() { - const plain = await this.takeScreenshot(); - const DateInputPlaceholder = this.browser.findElement({ css: '[data-tid~="DateFragmentsView__placeholder"]' }); - - await this.browser.actions({ bridge: true }).click(DateInputPlaceholder).perform(); - await delay(1000); - const focused = await this.takeScreenshot(); - - await this.expect([plain, focused]).to.matchImages(); - }, - }, - }, -}; - export const ShouldSetFocusOnPlaceholderClick: Story = () => { return ; }; ShouldSetFocusOnPlaceholderClick.storyName = 'should set focus on placeholder click'; -ShouldSetFocusOnPlaceholderClick.parameters = { - creevey: { - skip: { 'chrome only': { in: /^(?!\bchrome\b)/ } }, - tests: { - async focused() { - const DateInputPlaceholder = this.browser.findElement({ css: '[data-tid~="DateFragmentsView__placeholder"]' }); - - await this.browser.actions({ bridge: true }).click(DateInputPlaceholder).perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage(); - }, - }, - }, -}; diff --git a/packages/react-ui/components/DateInput/__tests__/DateInput-test.tsx b/packages/react-ui/components/DateInput/__tests__/DateInput-test.tsx index 86880153155..060c69763ac 100644 --- a/packages/react-ui/components/DateInput/__tests__/DateInput-test.tsx +++ b/packages/react-ui/components/DateInput/__tests__/DateInput-test.tsx @@ -63,7 +63,6 @@ describe('DateInput as InputlikeText', () => { rerender(); const input = getInput(); - // eslint-disable-next-line jest-dom/prefer-to-have-text-content expect(input.textContent).toBe(`99.09.${MASK_CHAR_EXEMPLAR.repeat(4)}`); }); @@ -118,11 +117,11 @@ describe('DateInput as InputlikeText', () => { KeyDownCases.forEach(([initDate, keys, expected]) => { const keyString = keys.join(' > '); const expectedDateStr = `"${expected}"`.padEnd(12, ' '); - it(`calls onValueChange with ${expectedDateStr} if value is "${initDate}" and pressed "${keyString}"`, () => { + it(`calls onValueChange with ${expectedDateStr} if value is "${initDate}" and pressed "${keyString}"`, async () => { const onValueChange = jest.fn(); render({ value: initDate, onValueChange }); const input = getInput(); - userEvent.click(input); + await userEvent.click(input); keys.forEach((key) => fireEvent.keyDown(input, { key })); @@ -196,11 +195,11 @@ describe('DateInput as InputlikeText', () => { KeyDownCases.forEach(([initDate, keys]) => { const keyString = keys.join(' > '); - it(`does not call onValueChange if value is "${initDate}", minDate is "${minDate}", maxDate is "${maxDate}" and pressed "${keyString}"`, () => { + it(`does not call onValueChange if value is "${initDate}", minDate is "${minDate}", maxDate is "${maxDate}" and pressed "${keyString}"`, async () => { const onValueChange = jest.fn(); render({ value: initDate, onValueChange, minDate, maxDate }); const input = getInput(); - userEvent.click(input); + await userEvent.click(input); keys.forEach((key) => fireEvent.keyDown(input, { key })); expect(onValueChange).not.toHaveBeenCalled(); @@ -224,11 +223,11 @@ describe('DateInput as InputlikeText', () => { const keyString = keys.join(' > '); const expectedDateStr = 'calls onValueChange with ' + `"${expected}"`.padEnd(12, ' '); - it(`${expectedDateStr} if value is "${initDate}", minDate is "${minDate}", maxDate is "${maxDate}" and pressed "${keyString}"`, () => { + it(`${expectedDateStr} if value is "${initDate}", minDate is "${minDate}", maxDate is "${maxDate}" and pressed "${keyString}"`, async () => { const onValueChange = jest.fn(); render({ value: initDate, onValueChange, minDate, maxDate }); const input = getInput(); - userEvent.click(input); + await userEvent.click(input); keys.forEach((key) => fireEvent.keyDown(input, { key })); const [value] = onValueChange.mock.calls[0]; @@ -252,21 +251,21 @@ describe('DateInput as InputlikeText', () => { expect(onKeyDown).toHaveBeenCalled(); }); - it('should handle onFocus event', () => { + it('should handle onFocus event', async () => { const onFocus = jest.fn(); renderRTL(); - userEvent.click(getInput()); + await userEvent.click(getInput()); expect(onFocus).toHaveBeenCalled(); }); - it('should handle onBlur event', () => { + it('should handle onBlur event', async () => { const onBlur = jest.fn(); renderRTL(); - userEvent.tab(); + await userEvent.tab(); expect(screen.getByTestId(InputLikeTextDataTids.root)).toHaveFocus(); - userEvent.tab(); + await userEvent.tab(); expect(screen.getByTestId(InputLikeTextDataTids.root)).not.toHaveFocus(); expect(onBlur).toHaveBeenCalled(); }); @@ -277,7 +276,7 @@ describe('DateInput as InputlikeText', () => { renderRTL(); const input = getInput(); - userEvent.dblClick(input); + await userEvent.dblClick(input); expect(screen.getByTestId(InputLikeTextDataTids.root)).toHaveFocus(); await delay(0); expect(getSelection()?.toString()).toBe(value); @@ -287,32 +286,29 @@ describe('DateInput as InputlikeText', () => { 2, )}.${MASK_CHAR_EXEMPLAR.repeat(4)}`; - it('should clear selected text in the input after pressing delete button', () => { + it('should clear selected text in the input after pressing delete button', async () => { renderRTL(); const input = getInput(); - userEvent.dblClick(input); - userEvent.keyboard('{delete}'); + await userEvent.dblClick(input); + await userEvent.keyboard('{delete}'); - // eslint-disable-next-line jest-dom/prefer-to-have-text-content expect(input.textContent).toBe(textContentWithMaskChars); }); - it('should clear selected text in the input after pressing backspace button', () => { + it('should clear selected text in the input after pressing backspace button', async () => { renderRTL(); const input = getInput(); - userEvent.dblClick(input); - userEvent.keyboard('{backspace}'); + await userEvent.dblClick(input); + await userEvent.keyboard('{backspace}'); - // eslint-disable-next-line jest-dom/prefer-to-have-text-content expect(input.textContent).toBe(textContentWithMaskChars); }); - it('should delete one char in DD by default after focus on element', () => { + it('should delete one char in DD by default after focus on element', async () => { renderRTL(); const input = getInput(); - userEvent.type(input, '{backspace}'); + await userEvent.type(input, '{backspace}'); - // eslint-disable-next-line jest-dom/prefer-to-have-text-content expect(input.textContent).toBe(`2${MASK_CHAR_EXEMPLAR.repeat(1)}.04.1988`); }); @@ -336,7 +332,7 @@ describe('DateInput as InputlikeText', () => { expect(screen.getByTestId(InputLikeTextDataTids.root)).not.toHaveFocus(); }); - it('blink method works', () => { + it('blink method works', async () => { const blinkMock = jest.fn(); const inputLikeTextRef = React.createRef(); renderRTL(); @@ -344,7 +340,7 @@ describe('DateInput as InputlikeText', () => { if (inputLikeTextRef.current) { inputLikeTextRef.current.blink = blinkMock; } - userEvent.type(getInput(), '{enter}'); + await userEvent.type(getInput(), '{enter}'); expect(blinkMock).toHaveBeenCalledTimes(1); }); diff --git a/packages/react-ui/components/DatePicker/DatePicker.tsx b/packages/react-ui/components/DatePicker/DatePicker.tsx index b78268186e0..dee49acf4d5 100644 --- a/packages/react-ui/components/DatePicker/DatePicker.tsx +++ b/packages/react-ui/components/DatePicker/DatePicker.tsx @@ -255,7 +255,7 @@ export class DatePicker extends React.PureComponent - + {this.renderMain} diff --git a/packages/react-ui/components/DatePicker/__creevey__/DatePicker.creevey.ts b/packages/react-ui/components/DatePicker/__creevey__/DatePicker.creevey.ts new file mode 100644 index 00000000000..35a74a0eddf --- /dev/null +++ b/packages/react-ui/components/DatePicker/__creevey__/DatePicker.creevey.ts @@ -0,0 +1,188 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('DatePicker', () => { + story('WithMouseeventHandlers', () => { + test('opened', async function () { + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); + + test('DateSelect month', async function () { + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .perform(); + await delay(1000); + await this.browser + .actions({ bridge: true }) + .click( + this.browser.findElement({ + css: '[data-tid="MonthView__month"]:first-child [data-tid="MonthView__headerMonth"] [data-tid="DateSelect__caption"]', + }), + ) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('DateSelect month'); + }); + + test('DateSelect year', async function () { + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .perform(); + await delay(1000); + await this.browser + .actions({ bridge: true }) + .click( + this.browser.findElement({ + css: '[data-comp-name~="MonthView"]:first-child [data-tid="MonthView__headerYear"] [data-tid="DateSelect__caption"]', + }), + ) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('DateSelect year'); + }); + }); + + story('DatePickerWithMinMaxDate', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + flaky: { + in: /^(?!\b(chrome|ie11)\b)/, + tests: ['DateSelect months', 'DateSelect years'], + }, + }, + }); + + test('DateSelect months', async function () { + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .pause(1000) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .click( + this.browser.findElement({ + css: '[data-tid="MonthView__month"]:first-child [data-tid="MonthView__headerMonth"] [data-tid="DateSelect__caption"]', + }), + ) + .pause(1000) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('DateSelect months'); + }); + + test('DateSelect years', async function () { + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .pause(1000) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .click( + this.browser.findElement({ + css: '[data-comp-name~="MonthView"]:first-child [data-tid="MonthView__headerYear"] [data-tid="DateSelect__caption"]', + }), + ) + .pause(1000) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('DateSelect years'); + }); + }); + + story('DatePickerInRelativeBody', () => { + test('opened', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="toggle-relative-position"]' })) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); + }); + + story('WithManualPosition', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } } }); + + test('opened top without relative position', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened top without relative position'); + }); + + test('opened bottom without relative position', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom without relative position'); + }); + + test('opened top with relative position', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="relative"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened top with relative position'); + }); + + test('opened bottom with relative position', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-tid~="relative"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom'); + }); + }); +}); diff --git a/packages/react-ui/components/DatePicker/__stories__/DatePicker.stories.tsx b/packages/react-ui/components/DatePicker/__stories__/DatePicker.stories.tsx index 13ca119e5f0..d047c3888d3 100644 --- a/packages/react-ui/components/DatePicker/__stories__/DatePicker.stories.tsx +++ b/packages/react-ui/components/DatePicker/__stories__/DatePicker.stories.tsx @@ -9,7 +9,7 @@ import { Gapped } from '../../Gapped'; import { Tooltip } from '../../Tooltip'; import { DatePicker } from '../DatePicker'; import { LocaleContext, LangCodes } from '../../../lib/locale'; -import { delay, emptyHandler } from '../../../lib/utils'; +import { emptyHandler } from '../../../lib/utils'; import { SizeProp } from '../../../lib/types/props'; interface DatePickerWithErrorProps { @@ -113,66 +113,6 @@ export const WithMouseeventHandlers: Story = () => { }; WithMouseeventHandlers.storyName = 'with mouseevent handlers'; -WithMouseeventHandlers.parameters = { - creevey: { - tests: { - async opened() { - await delay(1000); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) - .perform(); - await delay(1000); - await this.expect(await this.takeScreenshot()).to.matchImage('opened'); - }, - async 'DateSelect month'() { - await delay(1000); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) - .perform(); - await delay(1000); - await this.browser - .actions({ bridge: true }) - .click( - this.browser.findElement({ - css: '[data-tid="MonthView__month"]:first-child [data-tid="MonthView__headerMonth"] [data-tid="DateSelect__caption"]', - }), - ) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('DateSelect month'); - }, - async 'DateSelect year'() { - await delay(1000); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) - .perform(); - await delay(1000); - await this.browser - .actions({ bridge: true }) - .click( - this.browser.findElement({ - css: '[data-comp-name~="MonthView"]:first-child [data-tid="MonthView__headerYear"] [data-tid="DateSelect__caption"]', - }), - ) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('DateSelect year'); - }, - }, - }, -}; - export const WithMobileNativeDatePicker = () => { const [date, setDate] = useState('02.07.2017'); @@ -283,67 +223,6 @@ export const DatePickerWithMinMaxDate: Story = () => ( ); DatePickerWithMinMaxDate.storyName = 'DatePicker with min max date'; -DatePickerWithMinMaxDate.parameters = { - creevey: { - skip: { - flaky: { - in: /^(?!\b(chrome|ie11)\b)/, - tests: ['DateSelect months', 'DateSelect years'], - }, - }, - tests: { - async 'DateSelect months'() { - await delay(1000); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) - .pause(1000) - .perform(); - - await this.browser - .actions({ - bridge: true, - }) - .click( - this.browser.findElement({ - css: '[data-tid="MonthView__month"]:first-child [data-tid="MonthView__headerMonth"] [data-tid="DateSelect__caption"]', - }), - ) - .pause(1000) - .perform(); - - await this.expect(await this.takeScreenshot()).to.matchImage('DateSelect months'); - }, - async 'DateSelect years'() { - await delay(1000); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) - .pause(1000) - .perform(); - - await this.browser - .actions({ - bridge: true, - }) - .click( - this.browser.findElement({ - css: '[data-comp-name~="MonthView"]:first-child [data-tid="MonthView__headerYear"] [data-tid="DateSelect__caption"]', - }), - ) - .pause(1000) - .perform(); - - await this.expect(await this.takeScreenshot()).to.matchImage('DateSelect years'); - }, - }, - }, -}; - export const DatePickerLocaleProvider = () => { return (
@@ -390,25 +269,6 @@ export const DatePickerInRelativeBody: Story = () => { ); }; DatePickerInRelativeBody.storyName = 'DatePicker In Relative Body'; -DatePickerInRelativeBody.parameters = { - creevey: { - tests: { - async opened() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="toggle-relative-position"]' })) - .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) - .perform(); - - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened'); - }, - }, - }, -}; export const WithManualPosition: Story = () => { const [menuPos, setMenuPos] = useState<'top' | 'bottom'>('top'); @@ -439,66 +299,3 @@ export const WithManualPosition: Story = () => { ); }; WithManualPosition.storyName = 'with manual position'; -WithManualPosition.parameters = { - creevey: { - skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } }, - tests: { - async 'opened top without relative position'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) - .perform(); - - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened top without relative position'); - }, - async 'opened bottom without relative position'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) - .perform(); - - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom without relative position'); - }, - async 'opened top with relative position'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="relative"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) - .perform(); - - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened top with relative position'); - }, - async 'opened bottom with relative position'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-tid~="relative"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-comp-name~="DatePicker"]' })) - .perform(); - - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom'); - }, - }, - }, -}; diff --git a/packages/react-ui/components/DatePicker/__tests__/DatePicker-test.tsx b/packages/react-ui/components/DatePicker/__tests__/DatePicker-test.tsx index 60862877a3b..8b484c0497d 100644 --- a/packages/react-ui/components/DatePicker/__tests__/DatePicker-test.tsx +++ b/packages/react-ui/components/DatePicker/__tests__/DatePicker-test.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { render, screen } from '@testing-library/react'; +import { act, render, screen, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { componentsLocales as DateSelectLocalesRu } from '../../../internal/DateSelect/locale/locales/ru'; @@ -39,23 +39,23 @@ describe('DatePicker', () => { expect(screen.getByTestId(DatePickerDataTids.label)).toBeInTheDocument(); }); - it('renders date select when open', () => { + it('renders date select when open', async () => { render(); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId(CalendarDataTids.root)).toBeInTheDocument(); }); - it("doesn't open on focus if disabled", () => { + it("doesn't open on focus if disabled", async () => { render(); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.queryByTestId('Calendar')).not.toBeInTheDocument(); }); - it('closes when become disabled', () => { + it('closes when become disabled', async () => { const { rerender } = render(); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId(CalendarDataTids.root)).toBeInTheDocument(); rerender(); @@ -67,31 +67,32 @@ describe('DatePicker', () => { expect(screen.getByTestId(CalendarDataTids.root)).toBeInTheDocument(); }); - it('blur() methon works', () => { + it('blur() methon works', async () => { const datePickerRef = React.createRef(); render(); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId(CalendarDataTids.root)).toBeInTheDocument(); - - datePickerRef.current?.blur(); + act(() => { + datePickerRef.current?.blur(); + }); expect(screen.queryByTestId(CalendarDataTids.root)).not.toBeInTheDocument(); }); - it('handle onBlur event', () => { + it('handle onBlur event', async () => { const datePickerRef = React.createRef(); const onBlur = jest.fn(); render(); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId(CalendarDataTids.root)).toBeInTheDocument(); datePickerRef.current?.blur(); expect(onBlur).toHaveBeenCalled(); }); - it('handle onFocus event', () => { + it('handle onFocus event', async () => { const onFocus = jest.fn(); render(); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(onFocus).toHaveBeenCalled(); }); @@ -101,17 +102,17 @@ describe('DatePicker', () => { .setComponents(InternalDateGetter.getTodayComponents()) .toString({ withPad: true, withSeparator: true }); - it('render without LocaleProvider', () => { + it('render without LocaleProvider', async () => { render(); const expectedText = DatePickerLocaleHelper.get(defaultLangCode).today; const today = getToday({ langCode: defaultLangCode }); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId('Picker__todayWrapper')).toHaveTextContent(`${expectedText} ${today}`); }); - it('render default locale', () => { + it('render default locale', async () => { render( @@ -120,12 +121,12 @@ describe('DatePicker', () => { const expectedText = DatePickerLocaleHelper.get(defaultLangCode).today; const today = getToday({ langCode: defaultLangCode }); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId('Picker__todayWrapper')).toHaveTextContent(`${expectedText} ${today}`); }); - it('render correct locale when set langCode', () => { + it('render correct locale when set langCode', async () => { render( @@ -135,12 +136,12 @@ describe('DatePicker', () => { const expectedText = DatePickerLocaleHelper.get(LangCodes.en_GB).today; const today = getToday({ langCode: LangCodes.en_GB }); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId('Picker__todayWrapper')).toHaveTextContent(`${expectedText} ${today}`); }); - it('render custom locale', () => { + it('render custom locale', async () => { render( { const expectedText = DatePickerLocaleHelper.get(LangCodes.en_GB).today; const today = getToday({ langCode: LangCodes.en_GB, separator: InternalDateSeparator.Dash }); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId('Picker__todayWrapper')).toHaveTextContent(`${expectedText} ${today}`); }); - it('updates when langCode changes', () => { + it('updates when langCode changes', async () => { const { rerender } = render( @@ -173,12 +174,12 @@ describe('DatePicker', () => { , ); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId('Picker__todayWrapper')).toHaveTextContent(`${expectedText} ${today}`); }); - it('should rename months using locale', () => { + it('should rename months using locale', async () => { const renamedMonths = [ 'one', 'two', @@ -199,12 +200,12 @@ describe('DatePicker', () => { , ); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByText(renamedMonths[6])).toBeInTheDocument(); }); - it.each(['', null, undefined])('should clear the value when %s passed', (testValue) => { + it.each(['', null, undefined])('should clear the value when %s passed', async (testValue) => { const Comp = () => { const [value, setValue] = useState('24.08.2022'); @@ -221,12 +222,12 @@ describe('DatePicker', () => { const input = screen.getByTestId(InputLikeTextDataTids.input); expect(input).toHaveTextContent(/^24.08.2022$/); - userEvent.click(screen.getByRole('button', { name: 'Clear' })); + await userEvent.click(screen.getByRole('button', { name: 'Clear' })); const expected = 'ss.ss.ssss'.replace(/s/g, MASK_CHAR_EXEMPLAR); const expectedRegExp = new RegExp(`^${expected}$`); expect(input).toHaveTextContent(expectedRegExp, { normalizeWhitespace: false }); - userEvent.type(input, '24.08.2022'); + await userEvent.type(input, '24.08.2022'); expect(input).toHaveTextContent(/^24.08.2022$/); }); @@ -238,10 +239,10 @@ describe('DatePicker', () => { }); describe('a11y', () => { - it('sets value for aria-label attribute (ru)', () => { + it('sets value for aria-label attribute (ru)', async () => { render(); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId(DatePickerDataTids.pickerTodayWrapper)).toHaveAttribute( 'aria-label', @@ -249,14 +250,14 @@ describe('DatePicker', () => { ); }); - it('sets value for aria-label attribute (en)', () => { + it('sets value for aria-label attribute (en)', async () => { render( , ); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId(DatePickerDataTids.pickerTodayWrapper)).toHaveAttribute( 'aria-label', @@ -264,7 +265,7 @@ describe('DatePicker', () => { ); }); - it('sets custom value for `todayAriaLabel` locale', () => { + it('sets custom value for `todayAriaLabel` locale', async () => { const customAriaLabel = 'test'; render( @@ -272,11 +273,11 @@ describe('DatePicker', () => { , ); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getByTestId(DatePickerDataTids.pickerTodayWrapper)).toHaveAttribute('aria-label', customAriaLabel); }); - it('sets custom value for `selectMonthAriaLabel` locale', () => { + it('sets custom value for `selectMonthAriaLabel` locale', async () => { const customAriaLabel = 'test'; render( @@ -284,15 +285,16 @@ describe('DatePicker', () => { , ); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); - expect(screen.getAllByTestId(CalendarDataTids.headerMonth)[0].querySelector('button')).toHaveAttribute( + const monthButton = within(screen.getAllByTestId(CalendarDataTids.headerMonth)[0]).getByRole('button'); + expect(monthButton).toHaveAttribute( 'aria-label', `${DateSelectLocalesRu.selectChosenAriaLabel} ${customAriaLabel} Февраль`, ); }); - it('sets custom value for `selectYearAriaLabel` locale', () => { + it('sets custom value for `selectYearAriaLabel` locale', async () => { const customAriaLabel = 'test'; render( @@ -300,15 +302,16 @@ describe('DatePicker', () => { , ); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); - expect(screen.getAllByTestId(CalendarDataTids.headerYear)[0].querySelector('button')).toHaveAttribute( + const yearButton = within(screen.getAllByTestId(CalendarDataTids.headerYear)[0]).getByRole('button'); + expect(yearButton).toHaveAttribute( 'aria-label', `${DateSelectLocalesRu.selectChosenAriaLabel} ${customAriaLabel} 2021`, ); }); - it('sets custom value for `selectChosenAriaLabel` locale', () => { + it('sets custom value for `selectChosenAriaLabel` locale', async () => { const customAriaLabel = 'test'; render( @@ -316,15 +319,16 @@ describe('DatePicker', () => { , ); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); - expect(screen.getAllByTestId(CalendarDataTids.headerYear)[0].querySelector('button')).toHaveAttribute( + const yearButton = within(screen.getAllByTestId(CalendarDataTids.headerYear)[0]).getByRole('button'); + expect(yearButton).toHaveAttribute( 'aria-label', `${customAriaLabel} ${DateSelectLocalesRu.selectYearAriaLabel} 2021`, ); }); - it('sets custom value for `dayCellChooseDateAriaLabel` locale', () => { + it('sets custom value for `dayCellChooseDateAriaLabel` locale', async () => { const customAriaLabel = 'test'; const date = '1.2.2021'; render( @@ -333,7 +337,7 @@ describe('DatePicker', () => { , ); - userEvent.click(screen.getByTestId(DatePickerDataTids.input)); + await userEvent.click(screen.getByTestId(DatePickerDataTids.input)); expect(screen.getAllByTestId(CalendarDataTids.dayCell)[0]).toHaveAttribute( 'aria-label', diff --git a/packages/react-ui/components/Dropdown/__creevey__/Dropdown.creevey.ts b/packages/react-ui/components/Dropdown/__creevey__/Dropdown.creevey.ts new file mode 100644 index 00000000000..ea3d8256d70 --- /dev/null +++ b/packages/react-ui/components/Dropdown/__creevey__/Dropdown.creevey.ts @@ -0,0 +1,187 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('Dropdown', () => { + story('SimpleDropdown', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'MenuItem hover' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['MenuItem hover'] }, + }, + }); + + test('idle', async function () { + const element = await this.browser.findElement({ css: '.dropdown-test-container' }); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('idle'); + }); + + test('clicked', async function () { + const element = await this.browser.findElement({ css: '.dropdown-test-container' }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('clicked'); + }); + + test('MenuItem hover', async function () { + const element = await this.browser.findElement({ css: '.dropdown-test-container' }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' }), + }) + .perform(); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('MenuItem hover'); + }); + + test('selected item', async function () { + const element = await this.browser.findElement({ css: '.dropdown-test-container' }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' })) + .perform(); + await delay(1000); + await this.expect(await element.takeScreenshot()).to.matchImage('selected item'); + }); + }); + + story('WithMenuItemIcon', ({ setStoryParameters }) => { + setStoryParameters({ captureElement: '.dropdown-test-container' }); + + test('clicked', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); + }); + }); + + story('InsideScrollableContainer', ({ setStoryParameters }) => { + setStoryParameters({ captureElement: '.dropdown-test-container' }); + + test('scrolled', async function () { + await this.browser + .actions() + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + const opened = await this.takeScreenshot(); + await this.browser.executeScript(function () { + const scrollContainer = window.document.querySelector('.dropdown-test-container') as HTMLElement; + scrollContainer.scrollTop = scrollContainer.scrollHeight; + }); + const scrolled = await this.takeScreenshot(); + await this.expect({ opened, scrolled }).to.matchImages(); + }); + }); + + story('WithCustomSelectTheme', () => { + test('clicked', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); + }); + }); + + story('WithManualPosition', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } } }); + + test('opened top with portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened top with portal'); + }); + + test('opened bottom with portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom with portal'); + }); + + test('opened top without portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="portal"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened top without portal'); + }); + + test('opened bottom without portal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="portal"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom without portal'); + }); + }); + + story('Size', () => { + test('clicked all', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="open-all"]' })) + .pause(500) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('ClickedAll'); + }); + }); +}); diff --git a/packages/react-ui/components/Dropdown/__stories__/Dropdown.stories.tsx b/packages/react-ui/components/Dropdown/__stories__/Dropdown.stories.tsx index 70733ca10c6..a4b07f9d462 100644 --- a/packages/react-ui/components/Dropdown/__stories__/Dropdown.stories.tsx +++ b/packages/react-ui/components/Dropdown/__stories__/Dropdown.stories.tsx @@ -8,14 +8,13 @@ import { ThemeFactory } from '../../../lib/theming/ThemeFactory'; import { Meta, Story } from '../../../typings/stories'; import { Dropdown } from '../Dropdown'; import { MenuItem } from '../../MenuItem'; -import { delay } from '../../../lib/utils'; import { Gapped } from '../../Gapped'; import { MenuHeader } from '../../MenuHeader'; export default { title: 'Dropdown', decorators: [ - (Story) => ( + (Story: () => JSX.Element) => (
@@ -29,75 +28,6 @@ export const SimpleDropdown: Story = () => ( ); -SimpleDropdown.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'MenuItem hover' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['MenuItem hover'] }, - }, - tests: { - async idle() { - const element = await this.browser.findElement({ css: '.dropdown-test-container' }); - await delay(1000); - - await this.expect(await element.takeScreenshot()).to.matchImage('idle'); - }, - async clicked() { - const element = await this.browser.findElement({ css: '.dropdown-test-container' }); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) - .perform(); - await delay(1000); - - await this.expect(await element.takeScreenshot()).to.matchImage('clicked'); - }, - async 'MenuItem hover'() { - const element = await this.browser.findElement({ css: '.dropdown-test-container' }); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' }), - }) - .perform(); - await delay(1000); - - await this.expect(await element.takeScreenshot()).to.matchImage('MenuItem hover'); - }, - async 'selected item'() { - const element = await this.browser.findElement({ css: '.dropdown-test-container' }); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' })) - .perform(); - await delay(1000); - - await this.expect(await element.takeScreenshot()).to.matchImage('selected item'); - }, - }, - }, -}; - export const WithFixedWidth: Story = () => ( Menu item @@ -130,25 +60,6 @@ export const WithMenuItemIcon: Story = () => ( ); WithMenuItemIcon.storyName = 'With MenuItem icon'; -WithMenuItemIcon.parameters = { - creevey: { - captureElement: '.dropdown-test-container', - tests: { - async clicked() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); - }, - }, - }, -}; - export const WithIconAndOverflow = () => ( } caption="Lorem ipsum dollar all mubarak ibn ahmed" width="100px"> Menu item @@ -166,26 +77,6 @@ export const InsideScrollableContainer: Story = () => (
); -InsideScrollableContainer.parameters = { - creevey: { - captureElement: '.dropdown-test-container', - tests: { - async scrolled() { - await this.browser - .actions() - .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) - .perform(); - const opened = await this.takeScreenshot(); - await this.browser.executeScript(function () { - const scrollContainer = window.document.querySelector('.dropdown-test-container') as HTMLElement; - scrollContainer.scrollTop = scrollContainer.scrollHeight; - }); - const scrolled = await this.takeScreenshot(); - await this.expect({ opened, scrolled }).to.matchImages(); - }, - }, - }, -}; export const WithCustomSelectTheme: Story = () => { return ( @@ -206,22 +97,6 @@ export const WithCustomSelectTheme: Story = () => { }; WithCustomSelectTheme.storyName = 'with custom select theme'; -WithCustomSelectTheme.parameters = { - creevey: { - tests: { - async clicked() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); - }, - }, - }, -}; - export const WithManualPosition: Story = () => { const [menuPos, setMenuPos] = React.useState<'top' | 'bottom'>('top'); const [isPortalDisabled, setIsPortalDisabled] = React.useState(false); @@ -241,65 +116,6 @@ export const WithManualPosition: Story = () => { ); }; WithManualPosition.storyName = 'with manual position'; -WithManualPosition.parameters = { - creevey: { - skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } }, - tests: { - async 'opened top with portal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened top with portal'); - }, - async 'opened bottom with portal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom with portal'); - }, - async 'opened top without portal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="portal"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened top without portal'); - }, - async 'opened bottom without portal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="portal"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-comp-name~="Dropdown"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom without portal'); - }, - }, - }, -}; export const Size: Story = () => { const items = [one, 'two', three]; @@ -358,20 +174,3 @@ export const Size: Story = () => { ); }; Size.storyName = 'size'; -Size.parameters = { - creevey: { - tests: { - async 'clicked all'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="open-all"]' })) - .pause(500) - .perform(); - await delay(1000); - await this.expect(await this.takeScreenshot()).to.matchImage('ClickedAll'); - }, - }, - }, -}; diff --git a/packages/react-ui/components/Dropdown/__tests__/Dropdown-test.tsx b/packages/react-ui/components/Dropdown/__tests__/Dropdown-test.tsx index 27d19b5faf3..75033341083 100644 --- a/packages/react-ui/components/Dropdown/__tests__/Dropdown-test.tsx +++ b/packages/react-ui/components/Dropdown/__tests__/Dropdown-test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { act, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { Dropdown, DropdownDataTids } from '../Dropdown'; @@ -28,24 +28,24 @@ describe('Dropdown', () => { expect(screen.getByTestId(DropdownDataTids.root)).toBeInTheDocument(); }); - it('Renders items', () => { + it('Renders items', async () => { render({menuItem}); - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); expect(screen.getByText(menuItemText)).toBeInTheDocument(); }); - it('opens and closes', () => { + it('opens and closes', async () => { render({menuItem}); //is menu open check expect(screen.queryByTestId(MenuItemDataTids.root)).not.toBeInTheDocument(); - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); expect(screen.getByTestId(MenuItemDataTids.root)).toBeInTheDocument(); - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); expect(screen.queryByTestId(MenuItemDataTids.root)).not.toBeInTheDocument(); }); @@ -81,7 +81,9 @@ describe('Dropdown', () => { //is menu open check expect(screen.queryByTestId(MenuItemDataTids.root)).not.toBeInTheDocument(); - dropdownRef.current?.open(); + act(() => { + dropdownRef.current?.open(); + }); expect(screen.getByTestId(MenuItemDataTids.root)).toBeInTheDocument(); }); @@ -95,11 +97,13 @@ describe('Dropdown', () => { ); //is menu open check expect(screen.queryByTestId(MenuItemDataTids.root)).not.toBeInTheDocument(); - - dropdownRef.current?.open(); + act(() => { + dropdownRef.current?.open(); + }); expect(screen.getByTestId(MenuItemDataTids.root)).toBeInTheDocument(); - - dropdownRef.current?.close(); + act(() => { + dropdownRef.current?.close(); + }); expect(screen.queryByTestId(MenuItemDataTids.root)).not.toBeInTheDocument(); }); }); diff --git a/packages/react-ui/components/DropdownMenu/__creevey__/DropdownMenu.creevey.ts b/packages/react-ui/components/DropdownMenu/__creevey__/DropdownMenu.creevey.ts new file mode 100644 index 00000000000..96a1b8a8e38 --- /dev/null +++ b/packages/react-ui/components/DropdownMenu/__creevey__/DropdownMenu.creevey.ts @@ -0,0 +1,262 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +const outOfViewTests = (side: 'left' | 'right') => { + test('out of viewport', async function () { + if (side === 'left') { + await this.browser.executeScript(function () { + const container = window.document.querySelector('[data-tid="container"]') as HTMLElement; + container.scrollLeft = container.scrollWidth; + }); + } + + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="firstMenu"]' })) + .perform(); + await delay(1000); + + await this.expect(await this.takeScreenshot()).to.matchImage('out of viewport'); + }); + + test('out of edge with min menu width', async function () { + if (side === 'left') { + await this.browser.executeScript(function () { + const container = window.document.querySelector('[data-tid="container"]') as HTMLElement; + container.scrollLeft = container.scrollWidth; + }); + } + + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="secondMenu"]' })) + .perform(); + await delay(1000); + + await this.expect(await this.takeScreenshot()).to.matchImage('out of viewport with min menu width'); + }); +}; + +const textAlignmentTests = () => { + test('opened', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); +}; + +const navigateInNestedMenuItems = () => { + test('navigate', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) + .sendKeys(this.keys.DOWN) + .sendKeys(this.keys.DOWN) + .perform(); + const arrowDown = await this.browser.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ENTER) + .perform(); + await delay(1000); + const enter = await this.browser.takeScreenshot(); + await this.expect({ arrowDown, enter }).to.matchImages(); + }); +}; + +kind('DropdownMenu', () => { + story('SimpleExample', () => { + test('plain', async function () { + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('clickAfterClickedOnCaption', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('clickAfterClickedOnCaption'); + }); + + test('clicked', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); + }); + + test('tabPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); + }); + + test('enterPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ENTER) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('enterPress'); + }); + + test('escapePress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ENTER) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ESCAPE) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('escapePress'); + }); + }); + + story('CaptionWidth', () => { + test('plain', async function () { + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + }); + + story('WithHeaderAndFooter', () => { + test('clicked', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('clicked'); + }); + + test('scrolled by 100', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) + .perform(); + await this.browser.executeScript(function () { + const scrollContainer = window.document.querySelector('[data-tid~="ScrollContainer__inner"]') as HTMLElement; + scrollContainer.scrollTop += 100; + }); + await delay(2000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('scrolled by 100'); + }); + + test('scrolled down to bottom', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) + .perform(); + await this.browser.executeScript(function () { + const scrollContainer = window.document.querySelector('[data-tid~="ScrollContainer__inner"]') as HTMLElement; + scrollContainer.scrollTop += scrollContainer.scrollHeight; + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('scrolled down to bottom'); + }); + }); + + story('MobileExampleWithHorizontalPadding', ({ setStoryParameters }) => { + setStoryParameters({ captureElement: null }); + + test('opened', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-comp-name~="DropdownMenu"]' })) + .perform(); + await delay(200); + await this.browser + .actions({ bridge: true }) + .move({ origin: this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' }) }) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); + }); + story('MenuOutOfViewPortRight', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { flacky: { in: ['firefox2022', 'firefox2022Dark'] } }, + }); + outOfViewTests('right'); + }); + story('MenuOutOfViewPortLeft', () => { + outOfViewTests('left'); + }); + + story('WithItemsAndIcons', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }); + + textAlignmentTests(); + }); + + story('WithItemsAndIconsWithoutTextAlignment', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }); + + textAlignmentTests(); + }); + + story('WithNestedMenuItems', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }); + + navigateInNestedMenuItems(); + }); +}); diff --git a/packages/react-ui/components/DropdownMenu/__stories__/DropdownMenu.creevey.stories.tsx b/packages/react-ui/components/DropdownMenu/__stories__/DropdownMenu.creevey.stories.tsx deleted file mode 100644 index 2f0f78e0ffb..00000000000 --- a/packages/react-ui/components/DropdownMenu/__stories__/DropdownMenu.creevey.stories.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import React, { useState } from 'react'; - -import { delay } from '../../../lib/utils'; -import { Button } from '../../Button'; -import { CreeveyTests, Meta } from '../../../typings/stories'; -import { DropdownMenu } from '../DropdownMenu'; -import { MenuHeader } from '../../MenuHeader'; -import { MenuItem } from '../../MenuItem'; -import { OkIcon } from '../../../internal/icons/16px'; -import { PopupMenuDataTids } from '../../../internal/PopupMenu'; -import { ReactUIFeatureFlagsContext } from '../../../lib/featureFlagsContext'; - -export default { - title: 'DropdownMenu/Functional tests', - decorators: [ - (Story) => ( -
- -
- ), - ], - parameters: { - creevey: { - skip: { "themes don't affect logic": { in: /^(?!\bchrome\b)/ } }, - }, - }, -} as Meta; - -const textAlignmentTests: CreeveyTests = { - async opened() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: `[data-tid~="${PopupMenuDataTids.caption}"]` })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened'); - }, -}; - -export const WithItemsAndIcons = () => ( - Click me}> - MenuHeader - }>MenuItem1 - }>MenuItem2 - MenuItem3 - -); -WithItemsAndIcons.parameters = { - creevey: { - tests: textAlignmentTests, - skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, - }, -}; - -export const WithItemsAndIconsWithoutTextAlignment = () => ( - Click me}> - MenuHeader - }>MenuItem1 - }>MenuItem2 - MenuItem3 - -); -WithItemsAndIconsWithoutTextAlignment.parameters = { - creevey: { - tests: textAlignmentTests, - skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, - }, -}; - -const navigateInNestedMenuItems: CreeveyTests = { - async navigate() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: `[data-tid~="${PopupMenuDataTids.caption}"]` })) - .sendKeys(this.keys.DOWN) - .sendKeys(this.keys.DOWN) - .perform(); - const arrowDown = await this.browser.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.ENTER) - .perform(); - await delay(1000); - const enter = await this.browser.takeScreenshot(); - - await this.expect({ arrowDown, enter }).to.matchImages(); - }, -}; - -export const WithNestedMenuItems = () => { - const [caption, setCaption] = useState('not selected'); - const onClick = () => { - setCaption('selected'); - }; - return ( - - {caption}}> - <> -
- Раз - Два -
- Три - -
-
- ); -}; -WithNestedMenuItems.storyName = 'With nested menu items'; -WithNestedMenuItems.parameters = { - creevey: { - tests: navigateInNestedMenuItems, - }, -}; diff --git a/packages/react-ui/components/DropdownMenu/__stories__/DropdownMenu.stories.tsx b/packages/react-ui/components/DropdownMenu/__stories__/DropdownMenu.stories.tsx index 4bb864378f4..88dc5f2748e 100644 --- a/packages/react-ui/components/DropdownMenu/__stories__/DropdownMenu.stories.tsx +++ b/packages/react-ui/components/DropdownMenu/__stories__/DropdownMenu.stories.tsx @@ -1,11 +1,11 @@ -import React from 'react'; +import React, { useState } from 'react'; import MenuIcon from '@skbkontur/react-icons/Menu'; import ArrowSize2Icon from '@skbkontur/react-icons/ArrowSize2'; import SearchIcon from '@skbkontur/react-icons/Search'; import AddIcon from '@skbkontur/react-icons/Add'; import DeleteIcon from '@skbkontur/react-icons/Delete'; -import { Meta, Story, CreeveyTests } from '../../../typings/stories'; +import { Meta, Story } from '../../../typings/stories'; import { MenuItem } from '../../MenuItem'; import { MenuHeader } from '../../MenuHeader'; import { MenuSeparator } from '../../MenuSeparator'; @@ -14,12 +14,13 @@ import { Button } from '../../Button'; import { Toast } from '../../Toast'; import { Input } from '../../Input'; import { Gapped } from '../../Gapped'; -import { delay } from '../../../lib/utils'; +import { OkIcon } from '../../../internal/icons/16px'; +import { ReactUIFeatureFlagsContext } from '../../../lib/featureFlagsContext'; export default { title: 'DropdownMenu', decorators: [ - (Story) => ( + (Story: () => JSX.Element) => (
( ); SimpleExample.storyName = 'Simple example'; -SimpleExample.parameters = { - creevey: { - tests: { - async plain() { - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('plain'); - }, - async clickAfterClickedOnCaption() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('clickAfterClickedOnCaption'); - }, - async clicked() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); - }, - async tabPress() { - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); - }, - async enterPress() { - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.ENTER) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('enterPress'); - }, - async escapePress() { - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.ENTER) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.ESCAPE) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('escapePress'); - }, - }, - }, -}; - const MenuOutOfViewPortSample = ({ side }: { side: 'left' | 'right' }) => { return (
{ ); }; -const outOfViewTests: (side: 'left' | 'right') => CreeveyTests = (side) => { - return { - async 'out of viewport'() { - if (side === 'left') { - await this.browser.executeScript(function () { - const container = window.document.querySelector('[data-tid="container"]') as HTMLElement; - container.scrollLeft = container.scrollWidth; - }); - } - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="firstMenu"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('out of viewport'); - }, - async 'out of edge with min menu width'() { - if (side === 'left') { - await this.browser.executeScript(function () { - const container = window.document.querySelector('[data-tid="container"]') as HTMLElement; - container.scrollLeft = container.scrollWidth; - }); - } - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="secondMenu"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('out of viewport with min menu width'); - }, - }; -}; - export const MenuOutOfViewPortRight: Story = () => { return ; }; MenuOutOfViewPortRight.storyName = 'Menu out of viewport right'; -MenuOutOfViewPortRight.parameters = { - creevey: { - skip: { flacky: { in: ['firefox2022', 'firefox2022Dark'] } }, - tests: outOfViewTests('right'), - }, -}; - export const MenuOutOfViewPortLeft: Story = () => { return ; }; MenuOutOfViewPortLeft.storyName = 'Menu out of viewport left'; -MenuOutOfViewPortLeft.parameters = { - creevey: { - tests: outOfViewTests('left'), - }, -}; - export const CaptionWidth: Story = () => (
( ); CaptionWidth.storyName = 'Caption width 100%'; -CaptionWidth.parameters = { - creevey: { - tests: { - async plain() { - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('plain'); - }, - }, - }, -}; - export const ExampleWithWidthOfMenu = () => ( Открыть меню} menuWidth={350}> Заголовок меню @@ -377,54 +221,6 @@ export const WithHeaderAndFooter: Story = () => ( ); WithHeaderAndFooter.storyName = 'With header and footer'; -WithHeaderAndFooter.parameters = { - creevey: { - tests: { - async clicked() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.browser.takeScreenshot()).to.matchImage('clicked'); - }, - async 'scrolled by 100'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) - .perform(); - await this.browser.executeScript(function () { - const scrollContainer = window.document.querySelector('[data-tid~="ScrollContainer__inner"]') as HTMLElement; - scrollContainer.scrollTop += 100; - }); - await delay(2000); - - await this.expect(await this.browser.takeScreenshot()).to.matchImage('scrolled by 100'); - }, - async 'scrolled down to bottom'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="PopupMenu__caption"]' })) - .perform(); - await this.browser.executeScript(function () { - const scrollContainer = window.document.querySelector('[data-tid~="ScrollContainer__inner"]') as HTMLElement; - scrollContainer.scrollTop += scrollContainer.scrollHeight; - }); - await delay(1000); - - await this.expect(await this.browser.takeScreenshot()).to.matchImage('scrolled down to bottom'); - }, - }, - }, -}; - interface DropdownWithScrollStateChangeState { hasHeader: boolean; value: string; @@ -506,23 +302,43 @@ MobileExampleWithHorizontalPadding.parameters = { viewport: { defaultViewport: 'iphone', }, - creevey: { - captureElement: null, - tests: { - async opened() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-comp-name~="DropdownMenu"]' })) - .perform(); - await delay(200); - await this.browser - .actions({ bridge: true }) - .move({ origin: this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' }) }) - .perform(); - await delay(1000); +}; - await this.expect(await this.takeScreenshot()).to.matchImage('opened'); - }, - }, - }, +export const WithItemsAndIcons = () => ( + Click me}> + MenuHeader + }>MenuItem1 + }>MenuItem2 + MenuItem3 + +); + +export const WithItemsAndIconsWithoutTextAlignment = () => ( + Click me}> + MenuHeader + }>MenuItem1 + }>MenuItem2 + MenuItem3 + +); + +export const WithNestedMenuItems = () => { + const [caption, setCaption] = useState('not selected'); + const onClick = () => { + setCaption('selected'); + }; + return ( + + {caption}}> + <> +
+ Раз + Два +
+ Три + +
+
+ ); }; +WithNestedMenuItems.storyName = 'With nested menu items'; diff --git a/packages/react-ui/components/DropdownMenu/__tests__/DropdownMenu-test.tsx b/packages/react-ui/components/DropdownMenu/__tests__/DropdownMenu-test.tsx index a75c24444f7..bd486a86843 100644 --- a/packages/react-ui/components/DropdownMenu/__tests__/DropdownMenu-test.tsx +++ b/packages/react-ui/components/DropdownMenu/__tests__/DropdownMenu-test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { act, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { PopupDataTids } from '../../../internal/Popup'; @@ -27,19 +27,19 @@ describe('', () => { expect(renderNoCaption).toThrow(); }); - it('Contains after clicking on caption', () => { + it('Contains after clicking on caption', async () => { render( Test , ); expect(screen.queryByTestId(MenuDataTids.root)).not.toBeInTheDocument(); - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); expect(screen.getByTestId(MenuDataTids.root)).toBeInTheDocument(); }); - it("Contains 's after clicking on caption", () => { + it("Contains 's after clicking on caption", async () => { render( Test @@ -49,12 +49,12 @@ describe('', () => { ); expect(screen.queryByTestId(MenuItemDataTids.root)).not.toBeInTheDocument(); - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); expect(screen.getAllByTestId(MenuItemDataTids.root)).toHaveLength(3); }); - it('Click handler on menu item should be called before closing', () => { + it('Click handler on menu item should be called before closing', async () => { const onClick = jest.fn(); render( @@ -63,14 +63,14 @@ describe('', () => { , ); expect(screen.queryByTestId(MenuItemDataTids.root)).not.toBeInTheDocument(); - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); expect(screen.getByTestId(MenuItemDataTids.root)).toBeInTheDocument(); - userEvent.click(screen.getByTestId(MenuItemDataTids.root)); + await userEvent.click(screen.getByTestId(MenuItemDataTids.root)); expect(onClick).toHaveBeenCalled(); }); - it('Fire onOpen and onClose when open and close dropdown', () => { + it('Fire onOpen and onClose when open and close dropdown', async () => { const onOpen = jest.fn(); const onClose = jest.fn(); render( @@ -80,15 +80,15 @@ describe('', () => { ); // open - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); expect(onOpen.mock.calls).toHaveLength(1); // close - userEvent.click(screen.getByTestId(MenuItemDataTids.root)); + await userEvent.click(screen.getByTestId(MenuItemDataTids.root)); expect(onClose.mock.calls).toHaveLength(1); }); - it('Renders header', () => { + it('Renders header', async () => { const testHeader = 'testHeader'; render( Test header
}> @@ -96,11 +96,11 @@ describe('', () => { , ); - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); expect(screen.getByTestId(testHeader)).toBeInTheDocument(); }); - it('Renders footer', () => { + it('Renders footer', async () => { const testFooter = 'testFooter'; render( Test header
}> @@ -108,7 +108,7 @@ describe('', () => { , ); - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); expect(screen.getByTestId(testFooter)).toBeInTheDocument(); }); @@ -121,12 +121,13 @@ describe('', () => { Test , ); - - dropdownMenuRef.current?.open(); + act(() => { + dropdownMenuRef.current?.open(); + }); expect(screen.getByTestId(MenuItemDataTids.root)).toBeInTheDocument(); }); - it('Public method close() works', () => { + it('Public method close() works', async () => { const dropdownMenuRef = React.createRef(); render( @@ -134,20 +135,22 @@ describe('', () => { Test , ); - userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId(captionDatatid)); - dropdownMenuRef.current?.close(); + act(() => { + dropdownMenuRef.current?.close(); + }); expect(screen.queryByTestId(MenuItemDataTids.root)).not.toBeInTheDocument(); }); - it('prop `popupMenuId` sets an `id` for root of the popup', () => { + it('prop `popupMenuId` sets an `id` for root of the popup', async () => { const menuId = 'menu'; render( test} popupMenuId={menuId}>

test

, ); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); const menu = screen.getByTestId(PopupDataTids.root); expect(menu).toHaveAttribute('id', menuId); @@ -179,17 +182,17 @@ describe('', () => { ), ); it("doesn't highlight a not selectable MenuItem", async () => { - userEvent.click(screen.getByTestId(captionDatatid)); - userEvent.keyboard('{arrowdown}'); - userEvent.keyboard('{arrowdown}'); + await userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.keyboard('{arrowdown}'); + await userEvent.keyboard('{arrowdown}'); await delay(0); expect(screen.getByTestId('menuItem2')).not.toHaveAttribute('data-visual-state-hover', 'true'); expect(screen.getByTestId('menuItem3')).toHaveAttribute('data-visual-state-hover', 'true'); }); it("doesn't click on a not selectable MenuItem", async () => { - userEvent.click(screen.getByTestId(captionDatatid)); - userEvent.click(screen.getByTestId('menuItem2')); + await userEvent.click(screen.getByTestId(captionDatatid)); + await userEvent.click(screen.getByTestId('menuItem2')); await delay(0); expect(screen.getByTestId(MenuDataTids.root)).toBeInTheDocument(); }); diff --git a/packages/react-ui/components/FileUploader/FileUploader.tsx b/packages/react-ui/components/FileUploader/FileUploader.tsx index 08456d49c85..062a3e93085 100644 --- a/packages/react-ui/components/FileUploader/FileUploader.tsx +++ b/packages/react-ui/components/FileUploader/FileUploader.tsx @@ -189,16 +189,16 @@ const _FileUploader = forwardRefAndName('Fi ); const handleDrop = useCallback( - (event) => { + (event: DragEvent) => { if (disabled) { return; } const { dataTransfer } = event; - const { files } = dataTransfer; - - if (files?.length > 0) { - handleChange(files); + if (dataTransfer) { + if (dataTransfer.files?.length > 0) { + handleChange(dataTransfer.files); + } dataTransfer.clearData(); } }, diff --git a/packages/react-ui/components/FileUploader/UploadIcon.tsx b/packages/react-ui/components/FileUploader/UploadIcon.tsx index 4ee186164cc..7499f0f77a5 100644 --- a/packages/react-ui/components/FileUploader/UploadIcon.tsx +++ b/packages/react-ui/components/FileUploader/UploadIcon.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/display-name */ import React from 'react'; import { iconSizer } from '../../internal/icons2022/iconSizer'; diff --git a/packages/react-ui/components/FileUploader/__stories__/FileUploader.stories.tsx b/packages/react-ui/components/FileUploader/__stories__/FileUploader.stories.tsx index 5f94bce2cd8..77b2e90a7c4 100644 --- a/packages/react-ui/components/FileUploader/__stories__/FileUploader.stories.tsx +++ b/packages/react-ui/components/FileUploader/__stories__/FileUploader.stories.tsx @@ -9,7 +9,6 @@ export default { decorators: [(storyFn: () => JSX.Element) =>
{storyFn()}
], }; -// eslint-disable-next-line @typescript-eslint/no-empty-function const loadingRequest = () => new Promise(() => {}); const successRequest = () => diff --git a/packages/react-ui/components/FileUploader/__tests__/FileUploader-test.tsx b/packages/react-ui/components/FileUploader/__tests__/FileUploader-test.tsx index 941ce07efce..c5671f8cf65 100644 --- a/packages/react-ui/components/FileUploader/__tests__/FileUploader-test.tsx +++ b/packages/react-ui/components/FileUploader/__tests__/FileUploader-test.tsx @@ -1,4 +1,4 @@ -import React, { RefAttributes } from 'react'; +import React from 'react'; import { act } from 'react-dom/test-utils'; import { fireEvent, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; @@ -30,7 +30,7 @@ const getFilesList = () => { const addFiles = async (files: File[]) => { await act(async () => { - const input = screen.getByTestId(FileUploaderDataTids.root).querySelector('input[type="file"]'); + const input = screen.getByTestId(FileUploaderDataTids.input); if (input !== null) { fireEvent.change(input, { target: { files } }); } @@ -41,7 +41,7 @@ const addFiles = async (files: File[]) => { const removeFile = async () => { await act(async () => { - userEvent.click(screen.getByTestId(FileUploaderFileDataTids.fileIcon)); + await userEvent.click(screen.getByTestId(FileUploaderFileDataTids.fileIcon)); }); }; @@ -106,8 +106,7 @@ describe('FileUploader', () => { }); describe('Handlers', () => { - const renderComp = (props: FileUploaderProps & RefAttributes = {}) => - render(); + const renderComp = (props: FileUploaderProps) => render(); let file: File; const readFile = { @@ -126,7 +125,7 @@ describe('FileUploader', () => { const onFocus = jest.fn(); renderComp({ onFocus }); - userEvent.tab(); + await userEvent.tab(); const input = screen.getByTestId(FileUploaderDataTids.input); expect(input).toHaveFocus(); expect(onFocus).toHaveBeenCalledTimes(1); @@ -136,7 +135,7 @@ describe('FileUploader', () => { const onFocus = jest.fn(); renderComp({ onFocus, disabled: true }); - userEvent.tab(); + await userEvent.tab(); const input = screen.getByTestId(FileUploaderDataTids.input); expect(input).not.toHaveFocus(); @@ -149,7 +148,7 @@ describe('FileUploader', () => { const onBlur = jest.fn(); renderComp({ onBlur }); - userEvent.tab(); + await userEvent.tab(); const input = screen.getByTestId(FileUploaderDataTids.input); expect(input).toHaveFocus(); if (input !== null) { @@ -304,7 +303,7 @@ describe('FileUploader', () => { it('should handle onValueChange after reset', async () => { const onValueChange = jest.fn(); const ref = React.createRef(); - renderComp({ onValueChange, ref }); + render(); await addFiles([file]); @@ -464,13 +463,11 @@ describe('FileUploader', () => { expect(getBaseButtonContent()).toBe(expectedText); }; - // eslint-disable-next-line jest/expect-expect it('shouldn"t render files for multiple control', async () => { render(); await expectation(); }); - // eslint-disable-next-line jest/expect-expect it('shouldn"t render file for single control', async () => { render(); await expectation(); diff --git a/packages/react-ui/components/FxInput/FxInput.tsx b/packages/react-ui/components/FxInput/FxInput.tsx index b951225a66e..1402092ec9e 100644 --- a/packages/react-ui/components/FxInput/FxInput.tsx +++ b/packages/react-ui/components/FxInput/FxInput.tsx @@ -1,5 +1,3 @@ -// TODO: Enable this rule in functional components. -/* eslint-disable @typescript-eslint/no-unused-vars */ import React, { AriaAttributes } from 'react'; import PropTypes from 'prop-types'; diff --git a/packages/react-ui/components/FxInput/MathFunctionIcon.tsx b/packages/react-ui/components/FxInput/MathFunctionIcon.tsx index df9f9567cd5..055d289d7d7 100644 --- a/packages/react-ui/components/FxInput/MathFunctionIcon.tsx +++ b/packages/react-ui/components/FxInput/MathFunctionIcon.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/display-name */ import React from 'react'; import { iconSizer } from '../../internal/icons2022/iconSizer'; diff --git a/packages/react-ui/components/FxInput/UndoIcon.tsx b/packages/react-ui/components/FxInput/UndoIcon.tsx index fb4c9cd6d25..f35bfabd181 100644 --- a/packages/react-ui/components/FxInput/UndoIcon.tsx +++ b/packages/react-ui/components/FxInput/UndoIcon.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/display-name */ import React from 'react'; import { iconSizer } from '../../internal/icons2022/iconSizer'; diff --git a/packages/react-ui/components/FxInput/__creevey__/FxInput.creevey.ts b/packages/react-ui/components/FxInput/__creevey__/FxInput.creevey.ts new file mode 100644 index 00000000000..904233fb9c6 --- /dev/null +++ b/packages/react-ui/components/FxInput/__creevey__/FxInput.creevey.ts @@ -0,0 +1,21 @@ +import { story, kind, test } from 'creevey'; + +kind('FxInput', () => { + story('WithWidthStory', () => { + test('inside auto container', async function () { + const element = await this.browser.findElement({ css: '[data-tid="container"]' }); + await this.expect(await element.takeScreenshot()).to.matchImage('inside auto container'); + }); + + test('inside fixed container', async function () { + const element = await this.browser.findElement({ css: '[data-tid="container"]' }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#toggle-width' })) + .perform(); + await this.expect(await element.takeScreenshot()).to.matchImage('inside fixed container'); + }); + }); +}); diff --git a/packages/react-ui/components/FxInput/__stories__/FxInput.stories.tsx b/packages/react-ui/components/FxInput/__stories__/FxInput.stories.tsx index 617ce2bfd93..0a69695306e 100644 --- a/packages/react-ui/components/FxInput/__stories__/FxInput.stories.tsx +++ b/packages/react-ui/components/FxInput/__stories__/FxInput.stories.tsx @@ -39,27 +39,6 @@ Borderless.storyName = 'borderless'; export const WithWidthStory: Story = () => ; WithWidthStory.storyName = 'with width'; -WithWidthStory.parameters = { - creevey: { - tests: { - async 'inside auto container'() { - const element = await this.browser.findElement({ css: '[data-tid="container"]' }); - await this.expect(await element.takeScreenshot()).to.matchImage('inside auto container'); - }, - async 'inside fixed container'() { - const element = await this.browser.findElement({ css: '[data-tid="container"]' }); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#toggle-width' })) - .perform(); - await this.expect(await element.takeScreenshot()).to.matchImage('inside fixed container'); - }, - }, - }, -}; - interface TestFxInputProps { type: FxInputProps['type']; borderless?: boolean; @@ -116,7 +95,7 @@ interface TestWrapperProps { width?: number | string; ruler?: boolean; } -class TestWrapper extends React.Component { +class TestWrapper extends React.Component> { public render() { const { width, ruler, children } = this.props; const style: React.CSSProperties = { diff --git a/packages/react-ui/components/FxInput/__tests__/FxInput-test.tsx b/packages/react-ui/components/FxInput/__tests__/FxInput-test.tsx index ece8e24df1b..be519742f79 100644 --- a/packages/react-ui/components/FxInput/__tests__/FxInput-test.tsx +++ b/packages/react-ui/components/FxInput/__tests__/FxInput-test.tsx @@ -25,7 +25,7 @@ describe('FxInput', () => { expect(document.body).toHaveFocus(); }); - it.each(['', undefined])('should clear the value when %s passed', (testValue) => { + it.each(['', undefined])('should clear the value when %s passed', async (testValue) => { const Comp = () => { const [value, setValue] = useState('12345'); @@ -42,10 +42,10 @@ describe('FxInput', () => { const input = screen.getByRole('textbox'); expect(input).toHaveValue('12345'); - userEvent.click(screen.getByRole('button', { name: 'Clear' })); + await userEvent.click(screen.getByRole('button', { name: 'Clear' })); expect(input).toHaveValue(''); - userEvent.type(input, '123'); + await userEvent.type(input, '123'); expect(input).toHaveValue('123'); }); diff --git a/packages/react-ui/components/Gapped/__stories__/Gapped.stories.tsx b/packages/react-ui/components/Gapped/__stories__/Gapped.stories.tsx index 77f759d5641..deb92c0886f 100644 --- a/packages/react-ui/components/Gapped/__stories__/Gapped.stories.tsx +++ b/packages/react-ui/components/Gapped/__stories__/Gapped.stories.tsx @@ -7,7 +7,7 @@ import { Button } from '../../Button'; export default { title: 'Gapped', decorators: [ - (Story) => ( + (Story: () => JSX.Element) => (
diff --git a/packages/react-ui/components/GlobalLoader/GlobalLoader.tsx b/packages/react-ui/components/GlobalLoader/GlobalLoader.tsx index fa2d058aea6..de7df984c73 100644 --- a/packages/react-ui/components/GlobalLoader/GlobalLoader.tsx +++ b/packages/react-ui/components/GlobalLoader/GlobalLoader.tsx @@ -121,6 +121,7 @@ export class GlobalLoader extends React.Component { }); it('should set error', async () => { - GlobalLoader.start(); + act(() => { + GlobalLoader.start(); + }); await delay(DELAY_BEFORE_GLOBAL_LOADER_SHOW); expect(screen.getByTestId(GlobalLoaderDataTids.root)).toBeInTheDocument(); - GlobalLoader.reject(); + act(() => { + GlobalLoader.reject(); + }); expect(screen.getByTestId(GlobalLoaderDataTids.root)).toBeInTheDocument(); expect(screen.getByTestId(GlobalLoaderDataTids.root)).toHaveAttribute('data-status', 'error'); }); it('should set success', async () => { - GlobalLoader.start(); + act(() => { + GlobalLoader.start(); + }); await delay(DELAY_BEFORE_GLOBAL_LOADER_SHOW); expect(screen.getByTestId(GlobalLoaderDataTids.root)).toBeInTheDocument(); - GlobalLoader.done(); + act(() => { + GlobalLoader.done(); + }); expect(screen.getByTestId(GlobalLoaderDataTids.root)).toHaveAttribute('data-status', 'success'); await delay(DELAY_BEFORE_GLOBAL_LOADER_HIDE); @@ -199,10 +207,16 @@ describe('Global Loader', () => { }); it('should start after success animation', async () => { - GlobalLoader.start(); + act(() => { + GlobalLoader.start(); + }); await delay(DELAY_BEFORE_GLOBAL_LOADER_SHOW); - GlobalLoader.done(); - GlobalLoader.start(); + act(() => { + GlobalLoader.done(); + }); + act(() => { + GlobalLoader.start(); + }); await delay(DELAY_BEFORE_GLOBAL_LOADER_HIDE); expect(screen.queryByTestId(GlobalLoaderDataTids.root)).not.toBeInTheDocument(); diff --git a/packages/react-ui/components/Group/__creevey__/Group.creevey.ts b/packages/react-ui/components/Group/__creevey__/Group.creevey.ts new file mode 100644 index 00000000000..00f882d716b --- /dev/null +++ b/packages/react-ui/components/Group/__creevey__/Group.creevey.ts @@ -0,0 +1,19 @@ +import { story, kind, test } from 'creevey'; + +kind('Group', () => { + story('SimpleGroupWithInputAndButton', () => { + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('focused input', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'input' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('focused input'); + }); + }); +}); diff --git a/packages/react-ui/components/Group/__stories__/Group.stories.tsx b/packages/react-ui/components/Group/__stories__/Group.stories.tsx index 96f4bd544a0..e46b3d2b964 100644 --- a/packages/react-ui/components/Group/__stories__/Group.stories.tsx +++ b/packages/react-ui/components/Group/__stories__/Group.stories.tsx @@ -21,25 +21,6 @@ export const SimpleGroupWithInputAndButton: Story = () => ( ); SimpleGroupWithInputAndButton.storyName = 'Simple Group with Input and Button'; -SimpleGroupWithInputAndButton.parameters = { - creevey: { - tests: { - async plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('plain'); - }, - async 'focused input'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'input' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('focused input'); - }, - }, - }, -}; - export const SimpleGroupWithCustomInputsWidth = () => ( diff --git a/packages/react-ui/components/Group/__tests__/Group-test.tsx b/packages/react-ui/components/Group/__tests__/Group-test.tsx index 777757cd8dc..a7b622dead8 100644 --- a/packages/react-ui/components/Group/__tests__/Group-test.tsx +++ b/packages/react-ui/components/Group/__tests__/Group-test.tsx @@ -21,7 +21,6 @@ describe('Group', () => { render({undefined}); const wrappingElements = screen.getByTestId(GroupDataTids.root).childNodes; - // eslint-disable-next-line jest-dom/prefer-in-document expect(wrappingElements).toHaveLength(0); }); diff --git a/packages/react-ui/components/Hint/__creevey__/Hint.creevey.ts b/packages/react-ui/components/Hint/__creevey__/Hint.creevey.ts new file mode 100644 index 00000000000..b3edf5356e8 --- /dev/null +++ b/packages/react-ui/components/Hint/__creevey__/Hint.creevey.ts @@ -0,0 +1,67 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('Hint', () => { + story('SetManualAndOpenedPropOnClick', () => { + test('click on hint', async function () { + await this.browser + .actions() + .click(this.browser.findElement({ css: '#main' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('click on hint'); + }); + }); + + story('WithSVGIcon', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'internal logic being tested and not something UI related': { + in: [ + 'chromeDark', + 'chrome8px', + 'firefox8px', + 'firefox', + 'firefoxFlat8px', + 'firefoxDark', + 'ie118px', + 'ie11', + 'ie11Dark', + ], + }, + }, + }); + + test('idle', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('idle'); + }); + + test('hover', async function () { + await this.browser + .actions() + .move({ + origin: this.browser.findElement({ css: '[data-tid="icon"]' }), + }) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open'); + }); + }); + story('top bottom center', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b)/ } }, + }); + }); + story('KebabHintRemovePinFeatureFlag', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'only for 22 theme': { in: /^(?!\b.*2022.*\b)/ } }, + }); + }); + story('HintNearScreenEdge', ({ setStoryParameters }) => { + setStoryParameters({ + captureElement: 'body', + skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } }, + }); + }); +}); diff --git a/packages/react-ui/components/Hint/__stories__/Hint.stories.tsx b/packages/react-ui/components/Hint/__stories__/Hint.stories.tsx index 6d9acbec744..cd6d2bc02d4 100644 --- a/packages/react-ui/components/Hint/__stories__/Hint.stories.tsx +++ b/packages/react-ui/components/Hint/__stories__/Hint.stories.tsx @@ -6,7 +6,6 @@ import { Gapped } from '../../Gapped'; import { Input } from '../../Input'; import { PopupPositions } from '../../../internal/Popup'; import { Textarea } from '../../Textarea'; -import { delay } from '../../../lib/utils'; import { rootNode, TSetRootNode } from '../../../lib/rootNode'; import { Button } from '../../Button'; import { Tooltip } from '../../Tooltip'; @@ -15,7 +14,7 @@ import { ReactUIFeatureFlagsContext } from '../../../lib/featureFlagsContext'; export default { title: 'Hint', decorators: [ - (Story) => ( + (Story: () => JSX.Element) => (
@@ -79,11 +78,6 @@ export const TopBottomCenter = () => (
); TopBottomCenter.storyName = 'top bottom center'; -TopBottomCenter.parameters = { - creevey: { - skip: { in: /^(?!\bchrome\b)/ }, - }, -}; export const WithLargeWord = () => (
@@ -174,21 +168,6 @@ const HandleClickHint = () => { export const SetManualAndOpenedPropOnClick: Story = () => ; -SetManualAndOpenedPropOnClick.parameters = { - creevey: { - tests: { - async 'click on hint'() { - await this.browser - .actions() - .click(this.browser.findElement({ css: '#main' })) - .perform(); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('click on hint'); - }, - }, - }, -}; - export const WithSVGIcon: Story = () => { return ( @@ -199,42 +178,6 @@ export const WithSVGIcon: Story = () => { ); }; -WithSVGIcon.parameters = { - creevey: { - skip: { - 'internal logic being tested and not something UI related': { - in: [ - 'chromeDark', - 'chrome8px', - 'firefox8px', - 'firefox', - 'firefoxFlat8px', - 'firefoxDark', - 'ie118px', - 'ie11', - 'ie11Dark', - ], - }, - }, - tests: { - async idle() { - await this.expect(await this.takeScreenshot()).to.matchImage('idle'); - }, - async hover() { - await this.browser - .actions() - .move({ - origin: this.browser.findElement({ css: '[data-tid="icon"]' }), - }) - .perform(); - await delay(1000); - - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open'); - }, - }, - }, -}; - @rootNode class CustomClassComponent extends React.Component { private setRootNode!: TSetRootNode; @@ -260,11 +203,6 @@ export const KebabHintRemovePinFeatureFlag = () => ( ); KebabHintRemovePinFeatureFlag.storyName = 'with kebabHintRemovePin feature flag'; -KebabHintRemovePinFeatureFlag.parameters = { - creevey: { - skip: { in: /^(?!\b.*2022.*\b)/ }, - }, -}; export const HintNearScreenEdge = () => ( <> @@ -420,9 +358,3 @@ export const HintNearScreenEdge = () => ( ); HintNearScreenEdge.storyName = 'hint near screen edge'; -HintNearScreenEdge.parameters = { - creevey: { - captureElement: 'body', - skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } }, - }, -}; diff --git a/packages/react-ui/components/Hint/__tests__/Hint-test.tsx b/packages/react-ui/components/Hint/__tests__/Hint-test.tsx index 64f4edc150f..34dedc5522d 100644 --- a/packages/react-ui/components/Hint/__tests__/Hint-test.tsx +++ b/packages/react-ui/components/Hint/__tests__/Hint-test.tsx @@ -29,7 +29,7 @@ describe('Hint', () => { expect(hintContent).not.toBeInTheDocument(); }); - it('should open hint manually', () => { + it('should open hint manually', async () => { const hintText = 'world'; const Component = () => { const [isOpen, setIsOpen] = useState(false); @@ -50,13 +50,13 @@ describe('Hint', () => { expect(hintContent).not.toBeInTheDocument(); const openButton = screen.getByRole('button'); - userEvent.click(openButton); + await userEvent.click(openButton); const hintContentUpdated = screen.getByText(hintText); expect(hintContentUpdated).toBeInTheDocument(); }); - it('handels onMouseEnter event', () => { + it('handels onMouseEnter event', async () => { const onMouseEnter = jest.fn(); const hintChildrenText = 'Hello'; render( @@ -65,12 +65,12 @@ describe('Hint', () => { , ); - userEvent.hover(screen.getByText(hintChildrenText)); + await userEvent.hover(screen.getByText(hintChildrenText)); expect(onMouseEnter).toHaveBeenCalledTimes(1); }); - it('handels onMouseLeave event', () => { + it('handels onMouseLeave event', async () => { const onMouseLeave = jest.fn(); const hintChildrenText = 'Hello'; render( @@ -78,13 +78,12 @@ describe('Hint', () => { {hintChildrenText} , ); - userEvent.unhover(screen.getByText(hintChildrenText)); + await userEvent.unhover(screen.getByText(hintChildrenText)); expect(onMouseLeave).toHaveBeenCalledTimes(1); }); - it('clears timer after unmount', () => { - jest.useFakeTimers(); + it('clears timer after unmount', async () => { jest.spyOn(window, 'setTimeout'); jest.spyOn(window, 'clearTimeout'); @@ -99,7 +98,7 @@ describe('Hint', () => { // @ts-expect-error: Use of private property. expect(hintRef.current.timer).toBeUndefined(); - userEvent.hover(screen.getByText('Anchor')); + await userEvent.hover(screen.getByText('Anchor')); // @ts-expect-error: Use of private property. const { timer } = hintRef.current; diff --git a/packages/react-ui/components/Input/Input.tsx b/packages/react-ui/components/Input/Input.tsx index 5dfce9c0f8e..9fd4dd12a22 100644 --- a/packages/react-ui/components/Input/Input.tsx +++ b/packages/react-ui/components/Input/Input.tsx @@ -1,5 +1,4 @@ // TODO: Enable this rule in functional components. -/* eslint-disable @typescript-eslint/no-unused-vars */ import invariant from 'invariant'; import React, { AriaAttributes, ClassAttributes, HTMLAttributes, ReactElement } from 'react'; import warning from 'warning'; @@ -303,7 +302,7 @@ export class Input extends React.Component { {(theme) => { this.theme = theme; return ( - + {this.renderMain} ); diff --git a/packages/react-ui/components/Input/InputLayout/InputLayoutAsideIcon.tsx b/packages/react-ui/components/Input/InputLayout/InputLayoutAsideIcon.tsx index fe455e6631d..59c650466bf 100644 --- a/packages/react-ui/components/Input/InputLayout/InputLayoutAsideIcon.tsx +++ b/packages/react-ui/components/Input/InputLayout/InputLayoutAsideIcon.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { ReactElement } from 'react'; import { isElement } from 'react-is'; import { isKonturIcon } from '../../../lib/utils'; @@ -30,8 +30,8 @@ export const InputLayoutAsideIcon: React.FunctionComponent - {_icon} - - ) - ); + return _icon ? ( + + {_icon} + + ) : null; }; diff --git a/packages/react-ui/components/Input/InputLayout/InputLayoutAsideText.tsx b/packages/react-ui/components/Input/InputLayout/InputLayoutAsideText.tsx index b91b20db0af..14cefa87a5a 100644 --- a/packages/react-ui/components/Input/InputLayout/InputLayoutAsideText.tsx +++ b/packages/react-ui/components/Input/InputLayout/InputLayoutAsideText.tsx @@ -17,11 +17,9 @@ export const InputLayoutAsideText: React.FunctionComponent - {text} - - ) - ); + return text ? ( + + {text} + + ) : null; }; diff --git a/packages/react-ui/components/Input/__creevey__/Input.creevey.ts b/packages/react-ui/components/Input/__creevey__/Input.creevey.ts new file mode 100644 index 00000000000..30dc9eee991 --- /dev/null +++ b/packages/react-ui/components/Input/__creevey__/Input.creevey.ts @@ -0,0 +1,233 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +const differentStatesTest = () => { + test('Plain', async function () { + const element = await this.browser.findElement({ css: '#input' }); + await this.expect(await element.takeScreenshot()).to.matchImage('Plain'); + }); + + test('Focused', async function () { + const element = await this.browser.findElement({ css: '#input' }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#input input' })) + .pause(500) + .perform(); + await this.expect(await element.takeScreenshot()).to.matchImage('Focused'); + }); + + test('With typed text', async function () { + const element = await this.browser.findElement({ css: '#input' }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#input input' })) + .sendKeys('Test...') + .pause(500) + .perform(); + await this.expect(await element.takeScreenshot()).to.matchImage('With typed text'); + }); + + test('With long typed text', async function () { + const element = await this.browser.findElement({ css: '#input' }); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#input input' })) + .sendKeys('Test...') + .sendKeys('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') + .pause(500) + .perform(); + await this.expect(await element.takeScreenshot()).to.matchImage('With long typed text'); + }); +}; + +const testMaskedInput = () => { + test('idle, focus, edit, blur', async function () { + const click = (css: string) => { + return this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css })); + }; + const idle = await this.takeScreenshot(); + await click('input').pause(500).perform(); + const focused = await this.takeScreenshot(); + await click('input').sendKeys('953').perform(); + const edited = await this.takeScreenshot(); + await click('body').perform(); + const blured = await this.takeScreenshot(); + await this.expect({ idle, focused, edited, blured }).to.matchImages(); + }); +}; + +kind('Input', () => { + story('Default', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + differentStatesTest(); + }); + + story('WithMask', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + testMaskedInput(); + }); + + story('WithMaskAndCustomUnmaskedValue', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + "themes don't affect logic": { in: /^(?!\bchrome\b)/ }, + }, + }); + + testMaskedInput(); + }); + + story('SelectAllByProp', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + test('Plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); + }); + + test('Focused', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'label' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('Focused'); + }); + }); + + story('SelectAllByButton', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + test('Plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); + }); + + test('Selected', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="select-all"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('Selected'); + }); + }); + + story('MaxLength', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + differentStatesTest(); + }); + + story('UncontrolledInputWithPlaceholder', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + test('PlainAndTyped', async function () { + const plain = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'input' })) + .sendKeys('text') + .perform(); + const typed = await this.takeScreenshot(); + await this.expect({ plain, typed }).to.matchImages(); + }); + }); + + story('WithMaskAndSelectAllProp', ({ setStoryParameters }) => { + setStoryParameters({ skip: { "themes don't affect logic": { in: /^(?!\bchrome\b)/ } } }); + + test('PlainAndSelected', async function () { + const plain = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'input' })) + .pause(500) + .perform(); + const selectAllHalfFilledInput = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'input' })) + .sendKeys('1111') + .click(this.browser.findElement({ css: 'body' })) + .click(this.browser.findElement({ css: 'input' })) + .pause(500) + .perform(); + const selectAllFilledInput = await this.takeScreenshot(); + await this.expect({ plain, selectAllHalfFilledInput, selectAllFilledInput }).to.matchImages(); + }); + }); + + story('SearchTypeApi', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'tests only stable in chrome': { in: /^(?!\bchrome\b|\bchromeDark\b)/ }, + }, + }); + + test('Focused', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'label' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('Focused'); + }); + }); + + story('InputTypeApi', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b|\bchromeDark\b|\bfirefoxDark\b)/ }, + }, + }); + + test('Focused', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'label' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('Focused'); + }); + }); + story('Type', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'no themes': { in: /^(?!\b(chrome)\b)/ } }, + }); + }); + story('TypeApi', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'no themes': { in: /^(?!\b(chrome)\b)/ } }, + }); + }); +}); diff --git a/packages/react-ui/components/Input/__stories__/Input.creevey.stories.tsx b/packages/react-ui/components/Input/__stories__/Input.creevey.stories.tsx deleted file mode 100644 index 872958f36c6..00000000000 --- a/packages/react-ui/components/Input/__stories__/Input.creevey.stories.tsx +++ /dev/null @@ -1,311 +0,0 @@ -// TODO: Rewrite stories and enable rule (in process of functional refactoring). -/* eslint-disable react/no-unstable-nested-components */ -import React, { useState } from 'react'; - -import { delay } from '../../../lib/utils'; -import { CreeveyTests, Meta, Story } from '../../../typings/stories'; -import { Input } from '../Input'; - -export default { - title: 'Input/Functional tests', - parameters: { - creevey: { - skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, - }, - }, -} as Meta; - -const differentStatesTest: CreeveyTests = { - async Plain() { - const element = await this.browser.findElement({ css: '#input' }); - await this.expect(await element.takeScreenshot()).to.matchImage('Plain'); - }, - async Focused() { - const element = await this.browser.findElement({ css: '#input' }); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#input input' })) - .pause(500) - .perform(); - await this.expect(await element.takeScreenshot()).to.matchImage('Focused'); - }, - async 'With typed text'() { - const element = await this.browser.findElement({ css: '#input' }); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#input input' })) - .sendKeys('Test...') - .pause(500) - .perform(); - await this.expect(await element.takeScreenshot()).to.matchImage('With typed text'); - }, - async 'With long typed text'() { - const element = await this.browser.findElement({ css: '#input' }); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#input input' })) - .sendKeys('Test...') - .sendKeys('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') - .pause(500) - .perform(); - await this.expect(await element.takeScreenshot()).to.matchImage('With long typed text'); - }, -}; - -export const Default: Story = () => ( -
- -
-); - -Default.parameters = { - creevey: { - tests: differentStatesTest, - }, -}; - -const testMaskedInput: CreeveyTests = { - async 'idle, focus, edit, blur'() { - const click = (css: string) => { - return this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css })); - }; - - const idle = await this.takeScreenshot(); - - await click('input').pause(500).perform(); - const focused = await this.takeScreenshot(); - - await click('input').sendKeys('953').perform(); - const edited = await this.takeScreenshot(); - - await click('body').perform(); - const blured = await this.takeScreenshot(); - - await this.expect({ idle, focused, edited, blured }).to.matchImages(); - }, -}; - -export const WithMask: Story = () => ( - -); -WithMask.parameters = { - creevey: { - tests: testMaskedInput, - }, -}; - -export const WithMaskAndCustomUnmaskedValue: Story = () => { - const [value, setValue] = useState('+795'); - - return ( - setValue(value.replace(/\s/g, ''))} - /> - ); -}; - -WithMaskAndCustomUnmaskedValue.parameters = { - creevey: { - skip: { - flaky: { in: ['firefox'] }, - }, - tests: testMaskedInput, - }, -}; - -export const SelectAllByProp: Story = () => ; - -SelectAllByProp.parameters = { - creevey: { - tests: { - async Plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); - }, - async Focused() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'label' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('Focused'); - }, - }, - }, -}; - -export const SelectAllByButton: Story = () => { - let input: Input | null = null; - - const selectAll = () => { - if (input) { - input.selectAll(); - } - }; - - return ( -
-
- (input = element)} defaultValue="Some value" /> -
- -
- ); -}; -SelectAllByButton.storyName = 'Select all by button'; - -SelectAllByButton.parameters = { - creevey: { - tests: { - async Plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); - }, - async Selected() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="select-all"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('Selected'); - }, - }, - }, -}; - -export const MaxLength: Story = () => ( -
- -
-); - -MaxLength.parameters = { creevey: { tests: differentStatesTest } }; - -export const UncontrolledInputWithPlaceholder: Story = () => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [_value, setValue] = React.useState(); - return setValue(value)} />; -}; -UncontrolledInputWithPlaceholder.storyName = 'Uncontrolled Input with Placeholder'; -UncontrolledInputWithPlaceholder.parameters = { - creevey: { - tests: { - async PlainAndTyped() { - const plain = await this.takeScreenshot(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'input' })) - .sendKeys('text') - .perform(); - const typed = await this.takeScreenshot(); - await this.expect({ plain, typed }).to.matchImages(); - }, - }, - }, -}; - -export const WithMaskAndSelectAllProp: Story = () => { - const inputRef = React.useRef(null); - const [value, setValue] = React.useState('11'); - const selectAll = React.useCallback(() => { - inputRef.current?.selectAll(); - }, [inputRef.current]); - return ( -
- -
- ); -}; - -WithMaskAndSelectAllProp.parameters = { - creevey: { - skip: { "themes don't affect logic": { in: /^(?!\bchrome\b)/ } }, - tests: { - async PlainAndSelected() { - const plain = await this.takeScreenshot(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'input' })) - .pause(500) - .perform(); - const selectAllHalfFilledInput = await this.takeScreenshot(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'input' })) - .sendKeys('1111') - .click(this.browser.findElement({ css: 'body' })) - .click(this.browser.findElement({ css: 'input' })) - .pause(500) - .perform(); - const selectAllFilledInput = await this.takeScreenshot(); - await this.expect({ plain, selectAllHalfFilledInput, selectAllFilledInput }).to.matchImages(); - }, - }, - }, -}; - -export const SearchTypeApi: Story = () => ; -SearchTypeApi.parameters = { - creevey: { - skip: { - 'tests only stable in chrome': { in: /^(?!\bchrome\b|\bchromeDark\b)/ }, - }, - tests: { - async Focused() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'label' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('Focused'); - }, - }, - }, -}; - -export const InputTypeApi: Story = () => ; -InputTypeApi.parameters = { - creevey: { - skip: { - "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b|\bchromeDark\b|\bfirefoxDark\b)/ }, - }, - tests: { - async Focused() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'label' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('Focused'); - }, - }, - }, -}; diff --git a/packages/react-ui/components/Input/__stories__/Input.stories.tsx b/packages/react-ui/components/Input/__stories__/Input.stories.tsx index 202da3ec182..a197bc9ca74 100644 --- a/packages/react-ui/components/Input/__stories__/Input.stories.tsx +++ b/packages/react-ui/components/Input/__stories__/Input.stories.tsx @@ -1,6 +1,6 @@ // TODO: Rewrite stories and enable rule (in process of functional refactoring). /* eslint-disable react/no-unstable-nested-components */ -import React from 'react'; +import React, { useState } from 'react'; import SearchIcon from '@skbkontur/react-icons/Search'; import { ComponentTable } from '../../../internal/ComponentTable'; @@ -267,7 +267,6 @@ export const Type: Story = () => ( presetProps={{}} /> ); -Type.parameters = { creevey: { skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } } } }; const typeStates: InputState[] = [ { type: 'text', defaultValue: 'Value' }, @@ -307,9 +306,6 @@ export const TypeApi: Story = () => ( /> ); -TypeApi.parameters = { - creevey: { skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } } }, -}; const typeApiTypes: InputState[] = [ { type: 'number' }, @@ -381,3 +377,83 @@ export const BlinkingByButton: Story = () => { return ; }; BlinkingByButton.parameters = { creevey: { skip: true } }; + +export const Default: Story = () => ( +
+ +
+); + +export const WithMask: Story = () => ( + +); + +export const WithMaskAndCustomUnmaskedValue: Story = () => { + const [value, setValue] = useState('+795'); + + return ( + setValue(value.replace(/\s/g, ''))} + /> + ); +}; + +export const SelectAllByProp: Story = () => ; + +export const SelectAllByButton: Story = () => { + let input: Input | null = null; + + const selectAll = () => { + if (input) { + input.selectAll(); + } + }; + + return ( +
+
+ (input = element)} defaultValue="Some value" /> +
+ +
+ ); +}; +SelectAllByButton.storyName = 'Select all by button'; + +export const MaxLength: Story = () => ( +
+ +
+); + +export const UncontrolledInputWithPlaceholder: Story = () => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [_value, setValue] = React.useState(); + return setValue(value)} />; +}; +UncontrolledInputWithPlaceholder.storyName = 'Uncontrolled Input with Placeholder'; + +export const WithMaskAndSelectAllProp: Story = () => { + const inputRef = React.useRef(null); + const [value, setValue] = React.useState('11'); + const selectAll = React.useCallback(() => { + inputRef.current?.selectAll(); + }, [inputRef.current]); + return ( +
+ +
+ ); +}; + +export const SearchTypeApi: Story = () => ; + +export const InputTypeApi: Story = () => ; diff --git a/packages/react-ui/components/Input/__tests__/Input-test.tsx b/packages/react-ui/components/Input/__tests__/Input-test.tsx index 6a9c4275af0..331487c81ae 100644 --- a/packages/react-ui/components/Input/__tests__/Input-test.tsx +++ b/packages/react-ui/components/Input/__tests__/Input-test.tsx @@ -19,7 +19,6 @@ import { buildMountAttachTarget, getAttachedTarget } from '../../../lib/__tests_ describe('', () => { let consoleSpy: jest.SpyInstance; - // eslint-disable-next-line @typescript-eslint/no-empty-function beforeEach(() => (consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {}))); afterEach(() => consoleSpy.mockRestore()); @@ -41,15 +40,15 @@ describe('', () => { }); it('renders leftIcon', () => { - const leftIcon = ; + const leftIcon = ; render(); - expect(document.querySelector('.my-testy-icon')).toBeInTheDocument(); + expect(screen.getByTestId('my-testy-icon')).toBeInTheDocument(); }); it('renders rightIcon', () => { - const rightIcon = ; + const rightIcon = ; render(); - expect(document.querySelector('.my-testy-icon')).toBeInTheDocument(); + expect(screen.getByTestId('my-testy-icon')).toBeInTheDocument(); }); it('renders MaskedInput on mask prop', () => { @@ -80,7 +79,7 @@ describe('', () => { }); }); - it('type can be changed from allowed for masking to forbidden for masking', () => { + it('type can be changed from allowed for masking to forbidden for masking', async () => { const updatedType = 'date'; const Component = () => { const [type, setType] = useState('text'); @@ -94,12 +93,12 @@ describe('', () => { }; render(); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(consoleSpy.mock.calls[0][0]).toContain(`Warning: ${maskErrorMessage(updatedType)}`); }); - it(`prints an error if allowed type changed to forbidden when prop "mask" passed`, () => { + it(`prints an error if allowed type changed to forbidden when prop "mask" passed`, async () => { const updatedType = 'number'; const Component = () => { const [type, setType] = useState('text'); @@ -113,7 +112,7 @@ describe('', () => { }; render(); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(consoleSpy.mock.calls[0][0]).toContain(`Warning: ${maskErrorMessage(updatedType)}`); }); @@ -128,9 +127,9 @@ describe('', () => { expect(screen.getByRole('textbox')).toBeDisabled(); }); - it('cant focus element when its disabled', () => { + it('cant focus element when its disabled', async () => { render(); - userEvent.tab(); + await userEvent.tab(); expect(screen.getByRole('textbox')).not.toHaveFocus(); }); @@ -139,10 +138,10 @@ describe('', () => { expect(screen.getByRole('textbox')).toHaveAttribute('id', 'someId'); }); - it('maxLength prop works', () => { + it('maxLength prop works', async () => { render(); const element = screen.getByRole('textbox'); - userEvent.type(element, '123456'); + await userEvent.type(element, '123456'); expect(element).toHaveValue('12345'); }); @@ -156,11 +155,11 @@ describe('', () => { expect(screen.getByRole('textbox')).toHaveAttribute('title', 'someTitle'); }); - it('handels onClick event', () => { + it('handels onClick event', async () => { const onClick = jest.fn(); render(); const element = screen.getByRole('textbox'); - userEvent.click(element); + await userEvent.click(element); expect(onClick).toHaveBeenCalledTimes(1); }); @@ -178,19 +177,19 @@ describe('', () => { expect(onMouseDown).toHaveBeenCalledTimes(1); }); - it('handels onKeyUp event', () => { + it('handels onKeyUp event', async () => { const onKeyUp = jest.fn(); render(); - userEvent.type(screen.getByRole('textbox'), '{enter}'); + await userEvent.type(screen.getByRole('textbox'), '{enter}'); expect(onKeyUp).toHaveBeenCalledTimes(1); }); - it('handels onInput event', () => { + it('handels onInput event', async () => { const onInput = jest.fn(); render(); const element = screen.getByRole('textbox'); - userEvent.type(element, 'A'); + await userEvent.type(element, 'A'); expect(element).toHaveValue('A'); expect(onInput).toHaveBeenCalledTimes(1); }); @@ -202,12 +201,13 @@ describe('', () => { expect(onCopy).toHaveBeenCalledTimes(1); }); - it('handels onPaste event', () => { + it('handels onPaste event', async () => { const onPaste = jest.fn(); render(); const text = 'It handels onPaste event'; const element = screen.getByRole('textbox'); - userEvent.paste(element, text); + await userEvent.click(element); + await userEvent.paste(text); expect(element).toHaveValue(text); expect(onPaste).toHaveBeenCalledTimes(1); }); @@ -289,10 +289,10 @@ describe('', () => { }); selectionAllowedTypes.forEach((type) => { - it(`selectAllOnFocus prop works with type="${type}"`, () => { + it(`selectAllOnFocus prop works with type="${type}"`, async () => { const value = 'Prop works'; render(); - userEvent.tab(); + await userEvent.tab(); expect((document.activeElement as HTMLInputElement).selectionStart).toBe(0); expect((document.activeElement as HTMLInputElement).selectionEnd).toBe(value.length); @@ -300,9 +300,9 @@ describe('', () => { }); selectionForbiddenTypes.forEach((type) => { - it(`selectAllOnFocus prop doesn't work with type="${type}"`, () => { + it(`selectAllOnFocus prop doesn't work with type="${type}"`, async () => { render(); - userEvent.tab(); + await userEvent.tab(); expect((document.activeElement as HTMLInputElement).selectionStart).toBeNull(); expect((document.activeElement as HTMLInputElement).selectionEnd).toBeNull(); @@ -310,7 +310,7 @@ describe('', () => { }); }); - it('type can be changed from allowed for selection to forbidden for selection', () => { + it('type can be changed from allowed for selection to forbidden for selection', async () => { const value = 'value'; const updatedType = 'date'; const Component = () => { @@ -330,7 +330,7 @@ describe('', () => { expect((document.activeElement as HTMLInputElement).selectionStart).toBe(0); expect((document.activeElement as HTMLInputElement).selectionEnd).toBe(value.length); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); fireEvent.focus(screen.getByRole('textbox')); expect((document.activeElement as HTMLInputElement).selectionStart).toBeUndefined(); @@ -343,12 +343,11 @@ describe('', () => { expect(screen.getByRole('textbox')).not.toHaveAttribute('mask'); expect(consoleSpy).not.toHaveBeenCalled(); if (consoleSpy.mock.calls.length) { - // eslint-disable-next-line jest/no-conditional-expect expect(consoleSpy.mock.calls[0][0]).not.toContain('Warning: React does not recognize'); } }); - it('blink method works', () => { + it('blink method works', async () => { const blinkMock = jest.fn(); const refInput = React.createRef(); render(); @@ -356,29 +355,29 @@ describe('', () => { if (refInput.current) { refInput.current.blink = blinkMock; } - userEvent.type(screen.getByRole('textbox'), '{backspace}'); + await userEvent.type(screen.getByRole('textbox'), '{backspace}'); expect(blinkMock).toHaveBeenCalledTimes(1); }); - it('call handleUnexpectedInput', () => { + it('call handleUnexpectedInput', async () => { const unexpectedInputHandlerMock = jest.fn(); render(); const element = screen.getByRole('textbox'); - userEvent.type(element, '{backspace}'); + await userEvent.type(element, '{backspace}'); expect(unexpectedInputHandlerMock).toHaveBeenCalledTimes(1); - userEvent.type(element, '123'); + await userEvent.type(element, '123'); expect(screen.getByRole('textbox')).toHaveValue('123'); - userEvent.type(element, '{backspace}'); + await userEvent.type(element, '{backspace}'); expect(unexpectedInputHandlerMock).toHaveBeenCalledTimes(1); }); - it('should clear the value when an empty string passed', () => { + it('should clear the value when an empty string passed', async () => { const Comp = () => { const [value, setValue] = useState(''); @@ -395,49 +394,49 @@ describe('', () => { const input = screen.getByRole('textbox'); expect(input).toHaveValue(''); - userEvent.type(input, 'abc'); + await userEvent.type(input, 'abc'); expect(input).toHaveValue('abc'); - userEvent.click(screen.getByRole('button', { name: 'Clear' })); + await userEvent.click(screen.getByRole('button', { name: 'Clear' })); expect(input).toHaveValue(''); - userEvent.type(input, 'a'); + await userEvent.type(input, 'a'); expect(input).toHaveValue('a'); }); - it('handels onBlur event', () => { + it('handels onBlur event', async () => { const onBlur = jest.fn(); render(); - userEvent.click(screen.getByRole('textbox')); + await userEvent.click(screen.getByRole('textbox')); screen.getByRole('textbox').blur(); expect(onBlur).toHaveBeenCalledTimes(1); }); - it('handels onFocus event', () => { + it('handels onFocus event', async () => { const onFocus = jest.fn(); render(); - userEvent.click(screen.getByRole('textbox')); + await userEvent.click(screen.getByRole('textbox')); expect(onFocus).toHaveBeenCalledTimes(1); }); - it('handels onKeyDown event', () => { + it('handels onKeyDown event', async () => { const onKeyDown = jest.fn(); render(); - userEvent.type(screen.getByRole('textbox'), '{enter}'); + await userEvent.type(screen.getByRole('textbox'), '{enter}'); expect(onKeyDown).toHaveBeenCalledTimes(1); }); - it('handels onKeyPress event', () => { + it('handels onKeyPress event', async () => { const onKeyPress = jest.fn(); render(); - userEvent.type(screen.getByRole('textbox'), '{enter}'); + await userEvent.type(screen.getByRole('textbox'), '{enter}'); expect(onKeyPress).toHaveBeenCalledTimes(1); }); @@ -480,12 +479,12 @@ describe('', () => { expect(onMouseLeave).toHaveBeenCalledTimes(1); }); - it('maskedInput calls onUnexpectedInput', () => { + it('maskedInput calls onUnexpectedInput', async () => { const unexpectedInputHandlerMock = jest.fn(); render(); - userEvent.click(screen.getByRole('textbox')); - userEvent.keyboard('A'); + await userEvent.click(screen.getByRole('textbox')); + await userEvent.keyboard('A'); expect(unexpectedInputHandlerMock).toHaveBeenCalledTimes(1); }); diff --git a/packages/react-ui/components/Kebab/Kebab.tsx b/packages/react-ui/components/Kebab/Kebab.tsx index 894a2fc9a63..fcf7740de22 100644 --- a/packages/react-ui/components/Kebab/Kebab.tsx +++ b/packages/react-ui/components/Kebab/Kebab.tsx @@ -1,4 +1,4 @@ -import React, { AriaAttributes } from 'react'; +import React, { AriaAttributes, ReactElement } from 'react'; import PropTypes from 'prop-types'; import { isElement } from 'react-is'; import { globalObject } from '@skbkontur/global-object'; @@ -256,14 +256,14 @@ export class Kebab extends React.Component { private renderIcon2022() { const { size, icon = } = this.getProps(); - if (isElement(icon) && isKonturIcon(icon)) { + if (isElement(icon) && isKonturIcon(icon as ReactElement)) { const sizes: Record = { small: parseInt(this.theme.kebabIconSizeSmall), medium: parseInt(this.theme.kebabIconSizeMedium), large: parseInt(this.theme.kebabIconSizeLarge), }; - return React.cloneElement(icon, { + return React.cloneElement(icon as ReactElement, { size: icon.props.size ?? sizes[size], color: icon.props.color ?? this.theme.kebabIconColor, }); diff --git a/packages/react-ui/components/Kebab/KebabIcon.tsx b/packages/react-ui/components/Kebab/KebabIcon.tsx index 822c6d3d2c9..c4c08c0e865 100644 --- a/packages/react-ui/components/Kebab/KebabIcon.tsx +++ b/packages/react-ui/components/Kebab/KebabIcon.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/display-name */ import React from 'react'; import { iconSizer } from '../../internal/icons2022/iconSizer'; diff --git a/packages/react-ui/components/Kebab/__creevey__/Kebab.creevey.ts b/packages/react-ui/components/Kebab/__creevey__/Kebab.creevey.ts new file mode 100644 index 00000000000..3db0a8fd34e --- /dev/null +++ b/packages/react-ui/components/Kebab/__creevey__/Kebab.creevey.ts @@ -0,0 +1,169 @@ +import { story, kind, test } from 'creevey'; + +import { PopupMenuDataTids } from '../../../internal/PopupMenu'; +import { delay } from '../../../lib/utils'; +const textAlignmentTests = () => { + test('opened', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: `[data-tid~="${PopupMenuDataTids.caption}"]` })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); +}; + +const kebabTests = () => { + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('hovered', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: '[data-comp-name~="Kebab"]' }), + }) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); + }); + + test('clicked', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Kebab"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); + }); + + test('clickedOnButton2ndTime', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Kebab"]' })) + .click(this.browser.findElement({ css: '[data-comp-name~="Kebab"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('clickedOnButton2ndTime'); + }); + + test('tabPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); + }); + + test('enterPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .sendKeys(this.keys.ENTER) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('enterPress'); + }); +}; + +kind('Kebab', () => { + story('Small', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'hovered' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'clickedOnButton2ndTime'], + }, + }, + }); + + kebabTests(); + }); + + story('Medium', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'hovered' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'clickedOnButton2ndTime'], + }, + }, + }); + + kebabTests(); + }); + + story('Large', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'hovered' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'clickedOnButton2ndTime'], + }, + }, + }); + + kebabTests(); + }); + + story('KebabHintRemovePinFeatureFlag', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: /^(?!\b.*2022.*\b)/ }, + 'story-skip-1': { + in: /(?!\b.*2022.*\b)/, + tests: ['plain', 'hovered', 'clickedOnButton2ndTime', 'tabPress', 'enterPress'], + }, + }, + }); + + kebabTests(); + }); + + story('MobileExampleWithHorizontalPadding', ({ setStoryParameters }) => { + setStoryParameters({ captureElement: null }); + + test('opened', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-comp-name~="Kebab"]' })) + .perform(); + await delay(200); + await this.browser + .actions({ bridge: true }) + .move({ origin: this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' }) }) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('opened'); + }); + }); + story('WithItemsAndIcons', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }); + + textAlignmentTests(); + }); + + story('WithItemsAndIconsWithoutTextAlignment', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }); + + textAlignmentTests(); + }); +}); diff --git a/packages/react-ui/components/Kebab/__stories__/Kebab.creevey.stories.tsx b/packages/react-ui/components/Kebab/__stories__/Kebab.creevey.stories.tsx deleted file mode 100644 index 7674542e703..00000000000 --- a/packages/react-ui/components/Kebab/__stories__/Kebab.creevey.stories.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import React from 'react'; -import OkIcon from '@skbkontur/react-icons/Ok'; - -import { delay } from '../../../lib/utils'; -import { CreeveyTests, Meta } from '../../../typings/stories'; -import { MenuHeader } from '../../../components/MenuHeader'; -import { MenuItem } from '../../../components/MenuItem'; -import { PopupMenuDataTids } from '../../../internal/PopupMenu'; -import { Kebab } from '../Kebab'; - -export default { - title: 'Kebab/Functional tests', - decorators: [ - (Story) => ( -
- -
- ), - ], - parameters: { - creevey: { - skip: { "themes don't affect logic": { in: /^(?!\bchrome\b)/ } }, - }, - }, -} as Meta; - -const textAlignmentTests: CreeveyTests = { - async opened() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: `[data-tid~="${PopupMenuDataTids.caption}"]` })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened'); - }, -}; - -export const WithItemsAndIcons = () => ( -
- - MenuHeader - }>MenuItem1 - }>MenuItem2 - MenuItem3 - -
-); -WithItemsAndIcons.parameters = { - creevey: { - tests: textAlignmentTests, - skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, - }, -}; - -export const WithItemsAndIconsWithoutTextAlignment = () => ( -
- - MenuHeader - }>MenuItem1 - }>MenuItem2 - MenuItem3 - -
-); -WithItemsAndIconsWithoutTextAlignment.parameters = { - creevey: { - tests: textAlignmentTests, - skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, - }, -}; diff --git a/packages/react-ui/components/Kebab/__stories__/Kebab.stories.tsx b/packages/react-ui/components/Kebab/__stories__/Kebab.stories.tsx index 5d693c8b349..718bafcaf7c 100644 --- a/packages/react-ui/components/Kebab/__stories__/Kebab.stories.tsx +++ b/packages/react-ui/components/Kebab/__stories__/Kebab.stories.tsx @@ -3,11 +3,11 @@ import { action } from '@storybook/addon-actions'; import OkIcon from '@skbkontur/react-icons/Ok'; import { ReactUIFeatureFlagsContext } from '../../../lib/featureFlagsContext'; -import { Meta, Story, CreeveyTests } from '../../../typings/stories'; +import { Meta, Story } from '../../../typings/stories'; import { Kebab } from '../Kebab'; import { MenuItem } from '../../MenuItem'; import { KebabProps } from '..'; -import { delay } from '../../../lib/utils'; +import { MenuHeader } from '../../MenuHeader'; import { defaultItemsList, manyItemsList } from './Kebab.items'; @@ -16,65 +16,10 @@ interface KebabItem { action: string; } -const kebabTests: CreeveyTests = { - async plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('plain'); - }, - async hovered() { - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: '[data-comp-name~="Kebab"]' }), - }) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); - }, - async clicked() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Kebab"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); - }, - async clickedOnButton2ndTime() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Kebab"]' })) - .click(this.browser.findElement({ css: '[data-comp-name~="Kebab"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('clickedOnButton2ndTime'); - }, - async tabPress() { - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); - }, - async enterPress() { - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .sendKeys(this.keys.ENTER) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('enterPress'); - }, -}; - export default { title: 'Kebab', decorators: [ - (Story) => ( + (Story: () => JSX.Element) => (
; Small.storyName = '14px'; -Small.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'hovered' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { - in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], - tests: ['hovered', 'clickedOnButton2ndTime'], - }, - }, - tests: kebabTests, - }, -}; - export const Medium: Story = () => ; Medium.storyName = '18px'; -Medium.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'hovered' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { - in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], - tests: ['hovered', 'clickedOnButton2ndTime'], - }, - }, - tests: kebabTests, - }, -}; - export const Large: Story = () => ; Large.storyName = '20px'; -Large.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: 'hovered' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { - in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], - tests: ['hovered', 'clickedOnButton2ndTime'], - }, - }, - tests: kebabTests, - }, -}; - export const KebabHintRemovePinFeatureFlag: Story = () => { return ( @@ -150,18 +50,6 @@ export const KebabHintRemovePinFeatureFlag: Story = () => { ); }; KebabHintRemovePinFeatureFlag.storyName = 'with kebabHintRemovePin feature flag'; -KebabHintRemovePinFeatureFlag.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: /^(?!\b.*2022.*\b)/ }, - 'story-skip-1': { - in: /(?!\b.*2022.*\b)/, - tests: ['plain', 'hovered', 'clickedOnButton2ndTime', 'tabPress', 'enterPress'], - }, - }, - tests: kebabTests, - }, -}; export const KebabWithCustomIcon: Story = () => { return ( @@ -231,23 +119,26 @@ MobileExampleWithHorizontalPadding.parameters = { viewport: { defaultViewport: 'iphone', }, - creevey: { - captureElement: null, - tests: { - async opened() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-comp-name~="Kebab"]' })) - .perform(); - await delay(200); - await this.browser - .actions({ bridge: true }) - .move({ origin: this.browser.findElement({ css: '[data-comp-name~="MenuItem"]' }) }) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened'); - }, - }, - }, }; + +export const WithItemsAndIcons: Story = () => ( +
+ + MenuHeader + }>MenuItem1 + }>MenuItem2 + MenuItem3 + +
+); + +export const WithItemsAndIconsWithoutTextAlignment = () => ( +
+ + MenuHeader + }>MenuItem1 + }>MenuItem2 + MenuItem3 + +
+); diff --git a/packages/react-ui/components/Kebab/__tests__/Kebab-test.tsx b/packages/react-ui/components/Kebab/__tests__/Kebab-test.tsx index 10f781ed1af..5afb68765ed 100644 --- a/packages/react-ui/components/Kebab/__tests__/Kebab-test.tsx +++ b/packages/react-ui/components/Kebab/__tests__/Kebab-test.tsx @@ -7,47 +7,47 @@ import { MenuItem } from '../../../components/MenuItem'; import { Kebab, KebabDataTids } from '../Kebab'; describe('Kebab', () => { - it('prop `popupMenuId` sets an `id` for root of the popup', () => { + it('prop `popupMenuId` sets an `id` for root of the popup', async () => { const menuId = 'menu'; render(

test

, ); - userEvent.click(screen.getByTestId(KebabDataTids.caption)); + await userEvent.click(screen.getByTestId(KebabDataTids.caption)); const menu = screen.getByTestId(PopupDataTids.root); expect(menu).toHaveAttribute('id', menuId); }); - it('should focus by pressing tab', () => { + it('should focus by pressing tab', async () => { render(); - userEvent.tab(); + await userEvent.tab(); const kebab = screen.getByTestId(KebabDataTids.caption); expect(kebab).toHaveFocus(); }); - it('should handle blur by pressing tab', () => { + it('should handle blur by pressing tab', async () => { render(); - userEvent.tab(); + await userEvent.tab(); const kebab = screen.getByTestId(KebabDataTids.caption); expect(kebab).toHaveFocus(); - userEvent.tab(); + await userEvent.tab(); expect(kebab).not.toHaveFocus(); }); - it('should close by pressing escape', () => { + it('should close by pressing escape', async () => { const content = 'Kebab content'; render({content}); - userEvent.tab(); - userEvent.keyboard('{Enter}'); + await userEvent.tab(); + await userEvent.keyboard('{Enter}'); expect(screen.getByText(content)).toBeInTheDocument(); - userEvent.keyboard('{Escape}'); + await userEvent.keyboard('{Escape}'); const kebab = screen.getByTestId(KebabDataTids.caption); expect(kebab).toHaveFocus(); @@ -77,7 +77,7 @@ describe('Kebab', () => { expect(screen.getByRole('button')).toBeInTheDocument(); }); - it('should connect dropdown with button through aria-controls', () => { + it('should connect dropdown with button through aria-controls', async () => { render( test @@ -85,7 +85,7 @@ describe('Kebab', () => { ); const button = screen.getByRole('button'); - userEvent.click(button); + await userEvent.click(button); expect(button).toHaveAttribute('aria-controls', expect.stringContaining(PopupIds.root)); expect(screen.getByTestId(PopupDataTids.root)).toHaveAttribute('id', expect.stringContaining(PopupIds.root)); diff --git a/packages/react-ui/components/Link/__creevey__/Link.creevey.ts b/packages/react-ui/components/Link/__creevey__/Link.creevey.ts new file mode 100644 index 00000000000..db610e56dd1 --- /dev/null +++ b/packages/react-ui/components/Link/__creevey__/Link.creevey.ts @@ -0,0 +1,162 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +const focusedLinkTest = () => { + test('tab press', async function () { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: 'a' }), + }) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPressHovered'); + }); +}; +const linkTests = () => { + test('idle', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('idle'); + }); + + test('hover', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: 'a' }), + }) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('hover'); + }); +}; + +const focusedStyledLinkTest = () => { + test('tab press', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: 'a' }), + }) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: 'a' }), + }) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPressHovered'); + }); +}; + +kind('Link', () => { + story('Simple', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + // TODO @Khlutkova fix after update browsers + 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, + }, + }); + + linkTests(); + }); + + story('WithIcon', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + // TODO @Khlutkova fix after update browsers + 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, + 'story-skip-1': { in: /^(?!\b(chrome|firefox)(2022)*(Dark)*\b)/, tests: ['tab press'] }, + }, + }); + + linkTests(); + focusedLinkTest(); + }); + + story('Danger', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + // TODO @Khlutkova fix after update browsers + 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, + }, + }); + + linkTests(); + }); + + story('Grayed', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + // TODO @Khlutkova fix after update browsers + 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, + }, + }); + + linkTests(); + }); + + story('Disabled', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + // TODO @Khlutkova fix after update browsers + 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, + }, + }); + + linkTests(); + }); + + story('Loading', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + // TODO @Khlutkova fix after update browsers + 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, + }, + }); + + linkTests(); + }); + + story('FocusedStyledLink', ({ setStoryParameters }) => { + setStoryParameters({ skip: { flacky: { in: /^(?!\b(firefox2022)\b)/ } } }); + + focusedStyledLinkTest(); + }); + + story('WithLinkFocusOutlineFeatureFlag', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'hover does not work': { + in: /chrome/, + }, + }, + }); + + focusedStyledLinkTest(); + }); +}); diff --git a/packages/react-ui/components/Link/__stories__/Link.stories.tsx b/packages/react-ui/components/Link/__stories__/Link.stories.tsx index 2c1fd4279c6..2f9012f1d26 100644 --- a/packages/react-ui/components/Link/__stories__/Link.stories.tsx +++ b/packages/react-ui/components/Link/__stories__/Link.stories.tsx @@ -2,32 +2,14 @@ import React from 'react'; import OkIcon from '@skbkontur/react-icons/Ok'; import { CheckAIcon16Light } from '@skbkontur/icons/icons/CheckAIcon'; -import { Story, CreeveyTests } from '../../../typings/stories'; +import { Story } from '../../../typings/stories'; import { Link } from '../Link'; import { Toast } from '../../Toast'; import { Gapped } from '../../Gapped'; -import { delay } from '../../../lib/utils'; import { ThemeContext } from '../../../lib/theming/ThemeContext'; import { ThemeFactory } from '../../../lib/theming/ThemeFactory'; import { ReactUIFeatureFlagsContext } from '../../../lib/featureFlagsContext'; -const linkTests: CreeveyTests = { - async idle() { - await this.expect(await this.takeScreenshot()).to.matchImage('idle'); - }, - async hover() { - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: 'a' }), - }) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('hover'); - }, -}; - export default { title: 'Link', parameters: { @@ -39,39 +21,7 @@ export default { }, }; -const focusedLinkTest: CreeveyTests = { - async 'tab press'() { - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .perform(); - await delay(1000); - await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: 'a' }), - }) - .perform(); - await delay(1000); - await this.expect(await this.takeScreenshot()).to.matchImage('tabPressHovered'); - }, -}; - export const Simple: Story = () => Simple Link; -Simple.parameters = { - creevey: { - tests: linkTests, - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, - }, - }, -}; export const WithIcon: Story = () => { return ( @@ -97,57 +47,16 @@ export const WithIcon: Story = () => { ); }; -WithIcon.parameters = { - creevey: { - tests: { - idle: linkTests['idle'], - hover: linkTests['hover'], - 'tab press': focusedLinkTest['tab press'], - }, - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, - 'story-skip-1': { in: /^(?!\b(chrome|firefox)(2022)*(Dark)*\b)/, tests: ['tab press'] }, - }, - }, -}; export const Danger: Story = () => ( } use="danger"> Simple Link ); -Danger.parameters = { - creevey: { - tests: linkTests, - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, - }, - }, -}; export const Grayed: Story = () => Simple link; -Grayed.parameters = { - creevey: { - tests: linkTests, - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, - }, - }, -}; export const Disabled: Story = () => Simple link; -Disabled.parameters = { - creevey: { - tests: linkTests, - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, - }, - }, -}; export const WithOnClick = () => Toast.push('Clicked!')}>Simple Link; WithOnClick.storyName = 'With onClick'; @@ -171,46 +80,6 @@ export const Loading: Story = () => ( ); -Loading.parameters = { - creevey: { - tests: linkTests, - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hover'] }, - }, - }, -}; - -const focusedStyledLinkTest: CreeveyTests = { - async 'tab press'() { - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: 'a' }), - }) - .perform(); - await delay(1000); - await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: 'a' }), - }) - .perform(); - await delay(1000); - await this.expect(await this.takeScreenshot()).to.matchImage('tabPressHovered'); - }, -}; export const FocusedStyledLink: Story = () => { return ( @@ -224,26 +93,9 @@ export const FocusedStyledLink: Story = () => { ); }; -FocusedStyledLink.parameters = { - creevey: { - tests: focusedStyledLinkTest, - skip: { flacky: { in: /^(?!\b(firefox2022)\b)/ } }, - }, -}; export const WithLinkFocusOutlineFeatureFlag = () => ( Link ); - -WithLinkFocusOutlineFeatureFlag.parameters = { - creevey: { - tests: focusedStyledLinkTest, - skip: { - 'hover does not work': { - in: /chrome/, - }, - }, - }, -}; diff --git a/packages/react-ui/components/Link/__tests__/Link-test.tsx b/packages/react-ui/components/Link/__tests__/Link-test.tsx index 7fa5e457993..b6a5b5e7b9d 100644 --- a/packages/react-ui/components/Link/__tests__/Link-test.tsx +++ b/packages/react-ui/components/Link/__tests__/Link-test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { LinkProps } from '..'; @@ -8,31 +8,31 @@ import { Link, LinkDataTids } from '../Link'; const renderRTL = (props?: LinkProps) => render(); describe('Link', () => { - it('calls `onClick` when link clicked', () => { + it('calls `onClick` when link clicked', async () => { const onClick = jest.fn(); renderRTL({ onClick }); - userEvent.click(screen.getByTestId(LinkDataTids.root)); + await userEvent.click(screen.getByTestId(LinkDataTids.root)); expect(onClick).toHaveBeenCalled(); }); describe('disabled link', () => { - it('does not call `onClick` when link clicked', () => { + it('does not call `onClick` when link clicked', async () => { const onClick = jest.fn(); renderRTL({ onClick, disabled: true }); const linkElement = screen.getByTestId(LinkDataTids.root); - userEvent.click(linkElement, {}, { skipPointerEventsCheck: true }); + fireEvent.click(linkElement); expect(onClick).toHaveBeenCalledTimes(0); }); - it('does not call `onClick` when Enter pressed', () => { + it('does not call `onClick` when Enter pressed', async () => { const onClick = jest.fn(); renderRTL({ onClick, disabled: true }); - userEvent.type(screen.getByTestId(LinkDataTids.root), '{enter}'); + fireEvent.keyDown(screen.getByTestId(LinkDataTids.root), { key: 'Enter', code: 'Enter' }); expect(onClick).toHaveBeenCalledTimes(0); }); }); @@ -81,7 +81,7 @@ describe('Link', () => { const ariaLabel = 'aria-label'; render(); - expect(screen.getByRole('link')).toHaveAttribute('aria-label', ariaLabel); + expect(screen.getByTestId(LinkDataTids.root)).toHaveAttribute('aria-label', ariaLabel); }); }); }); diff --git a/packages/react-ui/components/Loader/__creevey__/Loader.creevey.ts b/packages/react-ui/components/Loader/__creevey__/Loader.creevey.ts new file mode 100644 index 00000000000..c908d6252b8 --- /dev/null +++ b/packages/react-ui/components/Loader/__creevey__/Loader.creevey.ts @@ -0,0 +1,34 @@ +import { story, kind, test } from 'creevey'; + +kind('Loader', () => { + story('ActiveLoader', () => { + test('covers children', async function () { + const element = await this.browser.findElement({ css: '[data-comp-name~="Loader"]' }); + const button = await this.browser.findElement({ css: '[data-comp-name~="Button"]' }); + await this.browser.actions({ bridge: true }).click(button).perform(); + await this.expect(await element.takeScreenshot()).to.matchImage('cover children'); + }); + }); + + story('InactiveLoader', () => { + test("doesn't cover children", async function () { + const element = await this.browser.findElement({ css: '[data-comp-name~="Loader"]' }); + const button = await this.browser.findElement({ css: '[data-comp-name~="Button"]' }); + await this.browser.actions({ bridge: true }).click(button).perform(); + await this.expect(await element.takeScreenshot()).to.matchImage("doesn't cover children"); + }); + }); + + story('FocusInside', () => { + test('focus inside', async function () { + const loader = await this.browser.findElement({ css: '[data-comp-name~="Loader"]' }); + const toggle = await this.browser.findElement({ css: '[data-tid~="toggle-loader"]' }); + await this.browser.actions().sendKeys(this.keys.TAB).perform(); + const enabled = await loader.takeScreenshot(); + await this.browser.actions().click(toggle).move({ x: 0, y: 0 }).click().perform(); + await this.browser.actions().sendKeys(this.keys.TAB).perform(); + const disabled = await loader.takeScreenshot(); + await this.expect({ enabled, disabled }).to.matchImages(); + }); + }); +}); diff --git a/packages/react-ui/components/Loader/__stories__/Loader.stories.tsx b/packages/react-ui/components/Loader/__stories__/Loader.stories.tsx index 80b24b63be4..599ca3d4db7 100644 --- a/packages/react-ui/components/Loader/__stories__/Loader.stories.tsx +++ b/packages/react-ui/components/Loader/__stories__/Loader.stories.tsx @@ -28,7 +28,7 @@ interface ContentComponentProps { additionalStyle?: AnyObject; loaderProps?: Partial; } -class ContentComponent extends React.Component { +class ContentComponent extends React.Component> { public render() { const { additionalStyle, loaderProps, children } = this.props; return ( @@ -221,39 +221,9 @@ BothDimensionsScrollableContentWithSpacesAround.parameters = { creevey: { skip: export const ActiveLoader: Story = () => ; ActiveLoader.storyName = 'Active loader'; -ActiveLoader.parameters = { - creevey: { - tests: { - async 'covers children'() { - const element = await this.browser.findElement({ css: '[data-comp-name~="Loader"]' }); - const button = await this.browser.findElement({ css: '[data-comp-name~="Button"]' }); - - await this.browser.actions({ bridge: true }).click(button).perform(); - - await this.expect(await element.takeScreenshot()).to.matchImage('cover children'); - }, - }, - }, -}; - export const InactiveLoader: Story = () => ; InactiveLoader.storyName = 'Inactive loader'; -InactiveLoader.parameters = { - creevey: { - tests: { - async "doesn't cover children"() { - const element = await this.browser.findElement({ css: '[data-comp-name~="Loader"]' }); - const button = await this.browser.findElement({ css: '[data-comp-name~="Button"]' }); - - await this.browser.actions({ bridge: true }).click(button).perform(); - - await this.expect(await element.takeScreenshot()).to.matchImage("doesn't cover children"); - }, - }, - }, -}; - export const WrapperWithCustomHeightAndInactiveLoader = () => ( {(theme) => { @@ -349,23 +319,3 @@ export const FocusInside: Story = () => {
); }; -FocusInside.parameters = { - creevey: { - tests: { - async 'focus inside'() { - const loader = await this.browser.findElement({ css: '[data-comp-name~="Loader"]' }); - const toggle = await this.browser.findElement({ css: '[data-tid~="toggle-loader"]' }); - - await this.browser.actions().sendKeys(this.keys.TAB).perform(); - const enabled = await loader.takeScreenshot(); - - await this.browser.actions().click(toggle).move({ x: 0, y: 0 }).click().perform(); - - await this.browser.actions().sendKeys(this.keys.TAB).perform(); - const disabled = await loader.takeScreenshot(); - - await this.expect({ enabled, disabled }).to.matchImages(); - }, - }, - }, -}; diff --git a/packages/react-ui/components/MaskedInput/__creevey__/MaskedInput.creevey.ts b/packages/react-ui/components/MaskedInput/__creevey__/MaskedInput.creevey.ts new file mode 100644 index 00000000000..60f9765cf5c --- /dev/null +++ b/packages/react-ui/components/MaskedInput/__creevey__/MaskedInput.creevey.ts @@ -0,0 +1,152 @@ +import { story, kind, test } from 'creevey'; + +const testMaskedInput = () => { + test('idle, focus, edit, blur', async function () { + const click = (css: string) => { + return this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css })); + }; + const idle = await this.takeScreenshot(); + await click('input').pause(500).perform(); + const focused = await this.takeScreenshot(); + await click('input').sendKeys('953').perform(); + const edited = await this.takeScreenshot(); + await click('body').perform(); + const blured = await this.takeScreenshot(); + await this.expect({ idle, focused, edited, blured }).to.matchImages(); + }); +}; + +const testIdleFocusBlur = () => { + test('idle, focus, blur', async function () { + const click = (css: string) => { + return this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css })); + }; + const idle = await this.takeScreenshot(); + await click('input').pause(500).perform(); + const focused = await this.takeScreenshot(); + await click('body').perform(); + const blured = await this.takeScreenshot(); + await this.expect({ idle, focused, blured }).to.matchImages(); + }); +}; + +const testRewriteInMiddle = () => { + test('idle, shift, rewrite', async function () { + const idle = await this.takeScreenshot(); + const input = await this.browser.findElement({ css: 'input' }); + this.browser + .actions({ bridge: true }) + .click(input) + .keyDown(this.keys.ARROW_LEFT) + .keyDown(this.keys.ARROW_LEFT) + .sendKeys('12') + .perform(); + const shift = await this.takeScreenshot(); + this.browser + .actions({ bridge: true }) + .click(input) + .keyDown(this.keys.ARROW_LEFT) + .keyDown(this.keys.ARROW_LEFT) + .sendKeys('56') + .perform(); + const rewrite = await this.takeScreenshot(); + await this.expect({ idle, shift, rewrite }).to.matchImages(); + }); +}; + +kind('MaskedInput', () => { + story('Default', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + testMaskedInput(); + }); + + story('IdleFocusBlur', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + testIdleFocusBlur(); + }); + + story('IdleFocusBlurWithPrefix', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + testIdleFocusBlur(); + }); + + story('WithCustomUnmaskedValue', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b)/ } }, + }); + testMaskedInput(); + }); + + story('SelectAllByProp', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + test('Plain focused', async function () { + const plain = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'label' })) + .perform(); + const focused = await this.takeScreenshot(); + await this.expect({ plain, focused }).to.matchImages(); + }); + }); + + story('SelectAllByButton', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + test('Plain, selected', async function () { + const plain = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="select-all"]' })) + .perform(); + const selected = await this.takeScreenshot(); + await this.expect({ plain, selected }).to.matchImages(); + }); + }); + + story('UncontrolledInputWithPlaceholder', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, + }); + test('PlainAndTyped', async function () { + const plain = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'input' })) + .sendKeys('text') + .perform(); + const typed = await this.takeScreenshot(); + await this.expect({ plain, typed }).to.matchImages(); + }); + }); + + story('RewriteInMiddle', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { "themes don't affect logic": { in: /^(?!\bchrome\b)/ } }, + }); + testRewriteInMiddle(); + }); +}); diff --git a/packages/react-ui/components/MaskedInput/__stories__/MaskedInput.creevey.stories.tsx b/packages/react-ui/components/MaskedInput/__stories__/MaskedInput.creevey.stories.tsx deleted file mode 100644 index 77d2b59ca6d..00000000000 --- a/packages/react-ui/components/MaskedInput/__stories__/MaskedInput.creevey.stories.tsx +++ /dev/null @@ -1,239 +0,0 @@ -// TODO: Rewrite stories and enable rule (in process of functional refactoring). -/* eslint-disable react/no-unstable-nested-components */ -import React, { useState } from 'react'; - -import { CreeveyTests, Meta, Story } from '../../../typings/stories'; -import { MaskedInput } from '../MaskedInput'; -import { Input } from '../../Input'; - -export default { - title: 'MaskedInput/Functional tests', - parameters: { - creevey: { - skip: { "themes don't affect logic": { in: /^(?!\bchrome\b|\bfirefox\b|\bie11\b)/ } }, - }, - }, -} as Meta; - -const testMaskedInput: CreeveyTests = { - async 'idle, focus, edit, blur'() { - const click = (css: string) => { - return this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css })); - }; - - const idle = await this.takeScreenshot(); - - await click('input').pause(500).perform(); - const focused = await this.takeScreenshot(); - - await click('input').sendKeys('953').perform(); - const edited = await this.takeScreenshot(); - - await click('body').perform(); - const blured = await this.takeScreenshot(); - - await this.expect({ idle, focused, edited, blured }).to.matchImages(); - }, -}; - -export const Default: Story = () => ( - -); -Default.parameters = { - creevey: { - tests: testMaskedInput, - }, -}; - -const testIdleFocusBlur: CreeveyTests = { - async 'idle, focus, blur'() { - const click = (css: string) => { - return this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css })); - }; - - const idle = await this.takeScreenshot(); - - await click('input').pause(500).perform(); - const focused = await this.takeScreenshot(); - - await click('body').perform(); - const blured = await this.takeScreenshot(); - - await this.expect({ idle, focused, blured }).to.matchImages(); - }, -}; - -export const IdleFocusBlur: Story = () => ( - -); - -IdleFocusBlur.parameters = { - creevey: { - tests: testIdleFocusBlur, - }, -}; - -export const IdleFocusBlurWithPrefix: Story = () => ( - -); - -IdleFocusBlurWithPrefix.parameters = { - creevey: { - tests: testIdleFocusBlur, - }, -}; - -export const WithCustomUnmaskedValue: Story = () => { - const [value, setValue] = useState('+795'); - - return ( - setValue(value.replace(/\s/g, ''))} - /> - ); -}; - -WithCustomUnmaskedValue.parameters = { - creevey: { - tests: testMaskedInput, - }, -}; - -export const SelectAllByProp: Story = () => ( - -); - -SelectAllByProp.parameters = { - creevey: { - tests: { - async 'Plain focused'() { - const plain = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'label' })) - .perform(); - - const focused = await this.takeScreenshot(); - await this.expect({ plain, focused }).to.matchImages(); - }, - }, - }, -}; - -export const SelectAllByButton: Story = () => { - let input: Input | null = null; - - const selectAll = () => { - if (input) { - input.selectAll(); - } - }; - - return ( -
-
- (input = element)} mask={'99:99'} defaultValue="12:34" /> -
- -
- ); -}; -SelectAllByButton.storyName = 'Select all by button'; - -SelectAllByButton.parameters = { - creevey: { - tests: { - async 'Plain, selected'() { - const plain = await this.takeScreenshot(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="select-all"]' })) - .perform(); - const selected = await this.takeScreenshot(); - - await this.expect({ plain, selected }).to.matchImages(); - }, - }, - }, -}; - -export const UncontrolledInputWithPlaceholder: Story = () => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [_value, setValue] = React.useState(); - return setValue(value)} />; -}; -UncontrolledInputWithPlaceholder.storyName = 'Uncontrolled Input with Placeholder'; -UncontrolledInputWithPlaceholder.parameters = { - creevey: { - tests: { - async PlainAndTyped() { - const plain = await this.takeScreenshot(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'input' })) - .sendKeys('text') - .perform(); - const typed = await this.takeScreenshot(); - await this.expect({ plain, typed }).to.matchImages(); - }, - }, - }, -}; - -const testRewriteInMiddle: CreeveyTests = { - async 'idle, shift, rewrite'() { - const idle = await this.takeScreenshot(); - - const input = await this.browser.findElement({ css: 'input' }); - this.browser - .actions({ bridge: true }) - .click(input) - .keyDown(this.keys.ARROW_LEFT) - .keyDown(this.keys.ARROW_LEFT) - .sendKeys('12') - .perform(); - const shift = await this.takeScreenshot(); - - this.browser - .actions({ bridge: true }) - .click(input) - .keyDown(this.keys.ARROW_LEFT) - .keyDown(this.keys.ARROW_LEFT) - .sendKeys('56') - .perform(); - const rewrite = await this.takeScreenshot(); - - await this.expect({ idle, shift, rewrite }).to.matchImages(); - }, -}; - -export const RewriteInMiddle: Story = () => ; - -RewriteInMiddle.parameters = { - creevey: { - tests: testRewriteInMiddle, - }, -}; diff --git a/packages/react-ui/components/MaskedInput/__stories__/MaskedInput.stories.tsx b/packages/react-ui/components/MaskedInput/__stories__/MaskedInput.stories.tsx index 9274eb06986..991c6684854 100644 --- a/packages/react-ui/components/MaskedInput/__stories__/MaskedInput.stories.tsx +++ b/packages/react-ui/components/MaskedInput/__stories__/MaskedInput.stories.tsx @@ -1,11 +1,10 @@ -// TODO: Rewrite stories and enable rule (in process of functional refactoring). -/* eslint-disable react/no-unstable-nested-components */ -import React from 'react'; +import React, { useState } from 'react'; import SearchIcon from '@skbkontur/react-icons/Search'; import { ComponentTable } from '../../../internal/ComponentTable'; import { Meta, Story } from '../../../typings/stories'; import { MaskedInput, MaskedInputProps } from '../MaskedInput'; +import { Input } from '../../Input'; export default { title: 'MaskedInput', @@ -23,6 +22,11 @@ export const Mask: Story = () => ( presetProps={{ mask: '(999) 999-99-99' }} /> ); +Mask.parameters = { + creevey: { + skip: { flaky: { in: /firefox/ } }, + }, +}; const maskStates: InputState[] = [ {}, @@ -126,3 +130,66 @@ const positionsStates: InputState[] = [ { value: 'WWWW WWWW WWW' }, { value: 'W1W1 W1W1 W1' }, ]; + +export const Default: Story = () => ( + +); + +export const IdleFocusBlur: Story = () => ( + +); + +export const IdleFocusBlurWithPrefix: Story = () => ( + +); + +export const WithCustomUnmaskedValue: Story = () => { + const [value, setValue] = useState('+795'); + + return ( + setValue(value.replace(/\s/g, ''))} + /> + ); +}; + +export const SelectAllByProp: Story = () => ( + +); + +export const SelectAllByButton: Story = () => { + let input: Input | null = null; + + const selectAll = () => { + if (input) { + input.selectAll(); + } + }; + + return ( +
+
+ (input = element)} mask={'99:99'} defaultValue="12:34" /> +
+ +
+ ); +}; +SelectAllByButton.storyName = 'Select all by button'; + +export const UncontrolledInputWithPlaceholder: Story = () => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [_value, setValue] = React.useState(); + return setValue(value)} />; +}; +UncontrolledInputWithPlaceholder.storyName = 'Uncontrolled Input with Placeholder'; + +export const RewriteInMiddle: Story = () => ; diff --git a/packages/react-ui/components/MaskedInput/__tests__/MaskedInput-test.tsx b/packages/react-ui/components/MaskedInput/__tests__/MaskedInput-test.tsx index 0df0d521b86..89991078985 100644 --- a/packages/react-ui/components/MaskedInput/__tests__/MaskedInput-test.tsx +++ b/packages/react-ui/components/MaskedInput/__tests__/MaskedInput-test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { fireEvent, render, screen } from '@testing-library/react'; +import { act, fireEvent, render, screen } from '@testing-library/react'; import { MaskedInput, MaskedInputProps } from '../MaskedInput'; @@ -88,7 +88,9 @@ describe('MaskedInput', () => { render(); const input = screen.getByRole('textbox'); - input.focus(); + act(() => { + input.focus(); + }); expect(input).toHaveValue('+7 ('); }); @@ -101,8 +103,10 @@ describe('MaskedInput', () => { render(); const input = screen.getByRole('textbox'); - input.focus(); - input.blur(); + act(() => { + input.focus(); + input.blur(); + }); expect(input).toHaveValue(expectedValue); }); @@ -112,7 +116,9 @@ describe('MaskedInput', () => { render(); const input = screen.getByRole('textbox'); - input.focus(); + act(() => { + input.focus(); + }); expect(valueChangeEvent).not.toHaveBeenCalled(); }); diff --git a/packages/react-ui/components/MenuItem/MenuItem.tsx b/packages/react-ui/components/MenuItem/MenuItem.tsx index e84b7219edf..f78072dc6c5 100644 --- a/packages/react-ui/components/MenuItem/MenuItem.tsx +++ b/packages/react-ui/components/MenuItem/MenuItem.tsx @@ -1,5 +1,3 @@ -// TODO: Enable this rule in functional components. -/* eslint-disable @typescript-eslint/no-unused-vars */ import React, { AriaAttributes } from 'react'; import PropTypes from 'prop-types'; import { globalObject, isBrowser } from '@skbkontur/global-object'; @@ -177,7 +175,7 @@ export class MenuItem extends React.Component { })} {...this.props} > - {this.renderMain} + {this.renderMain(this.props)}
); }} @@ -367,7 +365,7 @@ export class MenuItem extends React.Component { ref={this.contentRef} data-tid={MenuItemDataTids.content} > - {content} + {typeof content === 'function' ? content() : content} {this.props.comment && (
{ }); it('calls children function', () => { - render({(state) => state}); + render({(state) => state?.toString()}); expect(screen.getByTestId(MenuItemDataTids.root)).toHaveTextContent('hover'); }); @@ -100,7 +100,7 @@ describe('MenuItem', () => { }); describe('onMouseEnter', () => { - it('calls once', () => { + it('calls once', async () => { const onMouseEnter = jest.fn(); render( @@ -108,20 +108,20 @@ describe('MenuItem', () => { , ); - userEvent.hover(screen.getByRole('button')); - userEvent.hover(screen.getByText('MenuItem')); - userEvent.hover(screen.getByRole('button')); + await userEvent.hover(screen.getByRole('button')); + await userEvent.hover(screen.getByText('MenuItem')); + await userEvent.hover(screen.getByRole('button')); expect(onMouseEnter).toHaveBeenCalledTimes(1); }); - it('calls again after onMouseLeave', () => { + it('calls again after onMouseLeave', async () => { const onMouseEnter = jest.fn(); render(MenuItem); - userEvent.hover(screen.getByRole('button')); - userEvent.unhover(screen.getByRole('button')); - userEvent.hover(screen.getByRole('button')); + await userEvent.hover(screen.getByRole('button')); + await userEvent.unhover(screen.getByRole('button')); + await userEvent.hover(screen.getByRole('button')); expect(onMouseEnter.mock.calls).toHaveLength(2); }); diff --git a/packages/react-ui/components/MiniModal/MiniModalHeader.tsx b/packages/react-ui/components/MiniModal/MiniModalHeader.tsx index fc82036322b..55578b20f16 100644 --- a/packages/react-ui/components/MiniModal/MiniModalHeader.tsx +++ b/packages/react-ui/components/MiniModal/MiniModalHeader.tsx @@ -37,7 +37,12 @@ export const MiniModalHeader = forwardRefAndName )} {children && ( -
+
{children}
)} diff --git a/packages/react-ui/components/MiniModal/MiniModalIndent.tsx b/packages/react-ui/components/MiniModal/MiniModalIndent.tsx index a3834d9ce35..688b0c39c97 100644 --- a/packages/react-ui/components/MiniModal/MiniModalIndent.tsx +++ b/packages/react-ui/components/MiniModal/MiniModalIndent.tsx @@ -13,7 +13,7 @@ import { MiniModalDataTids } from './MiniModal'; * * @visibleName MiniModal.Indent */ -export const MiniModalIndent = forwardRefAndName( +export const MiniModalIndent = forwardRefAndName>( 'MiniModalIndent', ({ children, ...rest }, ref) => { const theme = useContext(ThemeContext); diff --git a/packages/react-ui/components/MiniModal/__stories__/MiniModal.stories.tsx b/packages/react-ui/components/MiniModal/__stories__/MiniModal.stories.tsx index d3feadbdd28..c940cfa981b 100644 --- a/packages/react-ui/components/MiniModal/__stories__/MiniModal.stories.tsx +++ b/packages/react-ui/components/MiniModal/__stories__/MiniModal.stories.tsx @@ -12,7 +12,7 @@ import { ThemeFactory } from '../../../lib/theming/ThemeFactory'; export default { title: 'MiniModal', - parameters: { creevey: { captureElement: '[data-testid="modal-content"]' } }, + parameters: { creevey: { captureElement: '[data-tid="modal-content"]' } }, } as Meta; export const Simple = () => ( diff --git a/packages/react-ui/components/Modal/__creevey__/Modal.creevey.ts b/packages/react-ui/components/Modal/__creevey__/Modal.creevey.ts new file mode 100644 index 00000000000..ca9e2a6533d --- /dev/null +++ b/packages/react-ui/components/Modal/__creevey__/Modal.creevey.ts @@ -0,0 +1,264 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +const topMiddleBottomModalTests = () => { + test('top', async function () { + await this.expect(await this.browser.takeScreenshot()).to.matchImage('top'); + }); + + test('middle', async function () { + await this.browser.executeScript(function () { + const modalContainer = window.document.querySelector('[data-tid="modal-container"]') as HTMLElement; + const modalContent = window.document.querySelector('[data-tid="modal-content"]') as HTMLElement; + + modalContainer.scrollTop = modalContent.offsetHeight / 2; + }); + await delay(100); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('middle'); + }); + + test('bottom', async function () { + await this.browser.executeScript(function () { + const modalContainer = window.document.querySelector('[data-tid="modal-container"]') as HTMLElement; + const modalContent = window.document.querySelector('[data-tid="modal-content"]') as HTMLElement; + + modalContainer.scrollTop = modalContent.offsetHeight; + }); + await delay(100); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('bottom'); + }); +}; + +kind('Modal', () => { + story('ModalWithFooterPanelStory', () => { + test('open modal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Button"]:nth-of-type(1)' })) + .perform(); + await delay(100); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); + }); + }); + + story('WithIconInput', () => { + test('open modal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); + }); + }); + + story('ModalOverAnotherModalStory', () => { + test('open first modal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-first-modal"]' })) + .perform(); + await delay(200); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open first modal'); + }); + + test('open second modal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-first-modal"]' })) + .perform(); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid~="open-second-modal"]' })) + .perform(); + await delay(100); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open second modal'); + }); + }); + + story('ModalWithoutFooterPanelStory', () => { + test('open modal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await delay(200); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); + }); + }); + + story('ModalWithoutFooterStory', () => { + test('open modal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); + }); + }); + + story('ModalMobileView', () => { + test('idle', async function () { + await this.expect(await this.browser.takeScreenshot()).to.matchImage('idle'); + }); + }); + + story('ModalWithVariableHeightOfContent', () => { + test('open modal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await delay(100); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); + }); + + test('toggle content height', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '#modal-inner [data-comp-name~="Toggle"]' })) + .pause(500) + .perform(); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('toggle content height'); + }); + }); + + story('ModalWithoutStickyElements', () => { + topMiddleBottomModalTests(); + }); + + story('SmallModalOnTheTop', () => { + test('open modal', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await delay(100); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); + }); + + test('close by click on the cross', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid="modal-close"]' })) + .perform(); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('close by click on the cross'); + }); + + test("doesn't close by click on the content", async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid="modal-content-button"]' })) + .perform(); + await this.expect(await this.browser.takeScreenshot()).to.matchImage("doesn't close by click on the content"); + }); + + test('closes by click on the background', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid="modal-container"]' })) + .perform(); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('closes by click on the background'); + }); + }); + + story('ModalWithChildrenFromOtherComponent', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: ['top', 'middle'] }, + }, + }); + + topMiddleBottomModalTests(); + }); + + story('MobileModal', () => { + test('top', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await delay(200); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('top'); + }); + + test('middle', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await delay(200); + await this.browser.executeScript(function () { + const modalContent = window.document.querySelector('.focus-lock-container') as HTMLElement; + const modalBody = window.document.querySelector('[data-comp-name~="Modal.Body"] ') as HTMLElement; + + modalContent.scrollTop = modalBody.offsetHeight / 2; + }); + await delay(100); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('middle'); + }); + + test('bottom', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) + .perform(); + await delay(200); + await this.browser.executeScript(function () { + const modalContent = window.document.querySelector('.focus-lock-container') as HTMLElement; + const modalBody = window.document.querySelector('[data-comp-name~="Modal.Body"] ') as HTMLElement; + + modalContent.scrollTop = modalBody.offsetHeight; + }); + await delay(100); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('bottom'); + }); + }); +}); diff --git a/packages/react-ui/components/Modal/__stories__/Modal.stories.tsx b/packages/react-ui/components/Modal/__stories__/Modal.stories.tsx index d6a3552ea09..88b3ba7715a 100644 --- a/packages/react-ui/components/Modal/__stories__/Modal.stories.tsx +++ b/packages/react-ui/components/Modal/__stories__/Modal.stories.tsx @@ -4,12 +4,11 @@ import React, { useState, useContext } from 'react'; import BorderAllIcon from '@skbkontur/react-icons/BorderAll'; import { ThemeFactory } from '../../../lib/theming/ThemeFactory'; -import { CreeveyTests, Story } from '../../../typings/stories'; +import { Story } from '../../../typings/stories'; import { Modal } from '../Modal'; import { Button } from '../../Button'; import { Input } from '../../Input'; import { Toggle } from '../../Toggle'; -import { delay } from '../../../lib/utils'; import { ThemeContext } from '../../../lib/theming/ThemeContext'; import { ResponsiveLayout } from '../../ResponsiveLayout'; @@ -208,23 +207,6 @@ const ModalWithFooterPanel = () => { export const ModalWithFooterPanelStory: Story = () => ; ModalWithFooterPanelStory.storyName = 'Modal with footer panel'; -ModalWithFooterPanelStory.parameters = { - creevey: { - tests: { - async 'open modal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Button"]:nth-of-type(1)' })) - .perform(); - await delay(100); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); - }, - }, - }, -}; - interface ModalWithoutFooterPanelState { opened: boolean; } @@ -347,7 +329,7 @@ interface ModalWithVariableHeightState { opened: boolean; panel: boolean; } -class ModalWithVariableHeight extends React.Component { +class ModalWithVariableHeight extends React.Component { public state: ModalWithVariableHeightState = { opened: false, panel: false, @@ -437,57 +419,9 @@ WithScrollableParentContent.parameters = { creevey: { skip: true } }; export const WithIconInput: Story = () => ; -WithIconInput.parameters = { - creevey: { - tests: { - async 'open modal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); - }, - }, - }, -}; - export const ModalOverAnotherModalStory: Story = () => ; ModalOverAnotherModalStory.storyName = 'Modal over another modal'; -ModalOverAnotherModalStory.parameters = { - creevey: { - tests: { - async 'open first modal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-first-modal"]' })) - .perform(); - await delay(200); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open first modal'); - }, - async 'open second modal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-first-modal"]' })) - .perform(); - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-tid~="open-second-modal"]' })) - .perform(); - await delay(100); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open second modal'); - }, - }, - }, -}; - export const DisabledModal = () => ( Disabled @@ -500,42 +434,9 @@ DisabledModal.parameters = { creevey: { skip: true } }; export const ModalWithoutFooterPanelStory: Story = () => ; ModalWithoutFooterPanelStory.storyName = 'Modal without footer panel'; -ModalWithoutFooterPanelStory.parameters = { - creevey: { - tests: { - async 'open modal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await delay(200); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); - }, - }, - }, -}; - export const ModalWithoutFooterStory: Story = () => ; ModalWithoutFooterStory.storyName = 'Modal without footer'; -ModalWithoutFooterStory.parameters = { - creevey: { - tests: { - async 'open modal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); - }, - }, - }, -}; - export const ModalWithoutHeader = () => ( @@ -577,13 +478,6 @@ export const ModalMobileView: Story = () => { ModalMobileView.storyName = 'Modal mobile view'; ModalMobileView.parameters = { viewport: { defaultViewport: 'iphone' }, - creevey: { - tests: { - async idle() { - await this.expect(await this.browser.takeScreenshot()).to.matchImage('idle'); - }, - }, - }, }; export const ModalWithVariableHeightOfContent: Story = () => ( @@ -593,63 +487,6 @@ export const ModalWithVariableHeightOfContent: Story = () => ( ); ModalWithVariableHeightOfContent.storyName = 'Modal with variable height of content'; -ModalWithVariableHeightOfContent.parameters = { - creevey: { - tests: { - async 'open modal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await delay(100); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); - }, - async 'toggle content height'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '#modal-inner [data-comp-name~="Toggle"]' })) - .pause(500) - .perform(); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('toggle content height'); - }, - }, - }, -}; - -const TopMiddleBottomModalTests: CreeveyTests = { - async top() { - await this.expect(await this.browser.takeScreenshot()).to.matchImage('top'); - }, - async middle() { - await this.browser.executeScript(function () { - const modalContainer = window.document.querySelector('[data-tid="modal-container"]') as HTMLElement; - const modalContent = window.document.querySelector('[data-tid="modal-content"]') as HTMLElement; - - modalContainer.scrollTop = modalContent.offsetHeight / 2; - }); - await delay(100); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('middle'); - }, - async bottom() { - await this.browser.executeScript(function () { - const modalContainer = window.document.querySelector('[data-tid="modal-container"]') as HTMLElement; - const modalContent = window.document.querySelector('[data-tid="modal-content"]') as HTMLElement; - - modalContainer.scrollTop = modalContent.offsetHeight; - }); - await delay(100); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('bottom'); - }, -}; - export const ModalWithoutStickyElements: Story = () => ( Header @@ -663,8 +500,6 @@ export const ModalWithoutStickyElements: Story = () => ( ); ModalWithoutStickyElements.storyName = 'Modal without sticky elements'; -ModalWithoutStickyElements.parameters = { creevey: { tests: TopMiddleBottomModalTests } }; - export const WithAlignTop = () => ( @@ -678,62 +513,6 @@ WithAlignTop.parameters = { creevey: { captureElement: null } }; export const SmallModalOnTheTop: Story = () => ; SmallModalOnTheTop.storyName = 'Small modal on the Top'; -SmallModalOnTheTop.parameters = { - creevey: { - tests: { - async 'open modal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await delay(100); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open modal'); - }, - async 'close by click on the cross'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-tid="modal-close"]' })) - .perform(); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('close by click on the cross'); - }, - async "doesn't close by click on the content"() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-tid="modal-content-button"]' })) - .perform(); - await this.expect(await this.browser.takeScreenshot()).to.matchImage("doesn't close by click on the content"); - }, - async 'closes by click on the background'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-tid="modal-container"]' })) - .perform(); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('closes by click on the background'); - }, - }, - }, -}; - export const ModalWithVeryLongHeaderWithoutSpaces = () => ( VeryLongAndStrangeHeaderWithoutMeaningAndSpaces @@ -811,15 +590,6 @@ export const ModalWithChildrenFromOtherComponent = () => ( ); -ModalWithChildrenFromOtherComponent.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Flat8px', 'ie11Dark'], tests: ['top', 'middle'] }, - }, - tests: TopMiddleBottomModalTests, - }, -}; - export const MobileModal: Story = () => { const [isOpen, setOpen] = useState(false); const [showThirdButton, setShowThird] = useState(false); @@ -886,56 +656,4 @@ MobileModal.parameters = { viewport: { defaultViewport: 'iphonePlus', }, - creevey: { - tests: { - async top() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await delay(200); - - await this.expect(await this.browser.takeScreenshot()).to.matchImage('top'); - }, - async middle() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await delay(200); - - await this.browser.executeScript(function () { - const modalContent = window.document.querySelector('.focus-lock-container') as HTMLElement; - const modalBody = window.document.querySelector('[data-comp-name~="ModalBody"] ') as HTMLElement; - - modalContent.scrollTop = modalBody.offsetHeight / 2; - }); - await delay(100); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('middle'); - }, - async bottom() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-modal"]' })) - .perform(); - await delay(200); - - await this.browser.executeScript(function () { - const modalContent = window.document.querySelector('.focus-lock-container') as HTMLElement; - const modalBody = window.document.querySelector('[data-comp-name~="ModalBody"] ') as HTMLElement; - - modalContent.scrollTop = modalBody.offsetHeight; - }); - - await delay(100); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('bottom'); - }, - }, - }, }; diff --git a/packages/react-ui/components/Modal/__tests__/Modal-test.tsx b/packages/react-ui/components/Modal/__tests__/Modal-test.tsx index 2e127ff925c..28c00609a4f 100644 --- a/packages/react-ui/components/Modal/__tests__/Modal-test.tsx +++ b/packages/react-ui/components/Modal/__tests__/Modal-test.tsx @@ -45,7 +45,7 @@ describe('Modal', () => { ).not.toThrow(); }); - it('Non-sticky header works', () => { + it('Non-sticky header works', async () => { const Component = () => { const [isSticky, setIsSticky] = useState(true); @@ -59,11 +59,11 @@ describe('Modal', () => { render(); expect(screen.getByTestId(StickyDataTids.root)).toBeInTheDocument(); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(screen.queryByTestId(StickyDataTids.root)).not.toBeInTheDocument(); }); - it('Non-sticky footer works', () => { + it('Non-sticky footer works', async () => { const Component = () => { const [isSticky, setIsSticky] = useState(true); @@ -77,11 +77,11 @@ describe('Modal', () => { render(); expect(screen.getByTestId(StickyDataTids.root)).toBeInTheDocument(); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(screen.queryByTestId(StickyDataTids.root)).not.toBeInTheDocument(); }); - it('onClose handler works', () => { + it('onClose handler works', async () => { const onCloseHandler = jest.fn(); render( @@ -89,7 +89,7 @@ describe('Modal', () => { , ); expect(onCloseHandler).not.toHaveBeenCalled(); - userEvent.click(screen.getByTestId(ModalDataTids.close)); + await userEvent.click(screen.getByTestId(ModalDataTids.close)); expect(onCloseHandler).toHaveBeenCalledTimes(1); }); diff --git a/packages/react-ui/components/Paging/ForwardIcon.tsx b/packages/react-ui/components/Paging/ForwardIcon.tsx index 07bc1acd2c6..6c8d3c51c86 100644 --- a/packages/react-ui/components/Paging/ForwardIcon.tsx +++ b/packages/react-ui/components/Paging/ForwardIcon.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/display-name */ import React from 'react'; import { ArrowCRightIcon16Light } from '../../internal/icons2022/ArrowCRightIcon/ArrowCRightIcon16Light'; diff --git a/packages/react-ui/components/Paging/__creevey__/Paging.creevey.ts b/packages/react-ui/components/Paging/__creevey__/Paging.creevey.ts new file mode 100644 index 00000000000..b188d924830 --- /dev/null +++ b/packages/react-ui/components/Paging/__creevey__/Paging.creevey.ts @@ -0,0 +1,99 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('Paging', () => { + story('GoToAbsensePageStory', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'hover' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hover', 'Move to page by Ender'], + }, + flaky: { + in: ['firefox2022', 'firefox2022Dark'], + tests: ['Move focus right', 'Move to page by Ender'], + }, + }, + }); + + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('hover', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` }), + }) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('hover'); + }); + + test('change page by number', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('change page by number'); + }); + + test('change page by forwardLink', async function () { + // NOTE Firefox bug if click send right after click from previous test it results as double click + await delay(500); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: `[data-tid='Paging__forwardLink']` })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('change page by forwardLink'); + }); + + test('focused', async function () { + // NOTE Firefox bug if click send right after click from previous test it results as double click + await delay(500); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('focused'); + }); + + test('Move focus right', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` })) + .pause(100) + .sendKeys(this.keys.ARROW_RIGHT) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('Move focus right'); + }); + + test('Move to page by Ender', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` })) + .pause(100) + .sendKeys(this.keys.ARROW_RIGHT) + .pause(100) + .sendKeys(this.keys.ENTER) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('Move to page by Ender'); + }); + }); +}); diff --git a/packages/react-ui/components/Paging/__stories__/Paging.stories.tsx b/packages/react-ui/components/Paging/__stories__/Paging.stories.tsx index 423bbd2b01b..ca0a6ed64be 100644 --- a/packages/react-ui/components/Paging/__stories__/Paging.stories.tsx +++ b/packages/react-ui/components/Paging/__stories__/Paging.stories.tsx @@ -4,7 +4,7 @@ import { ComponentStory } from '@storybook/react'; import { Meta, Story } from '../../../typings/stories'; import { ItemComponentProps, Paging } from '../Paging'; -import { delay, emptyHandler } from '../../../lib/utils'; +import { emptyHandler } from '../../../lib/utils'; import { PagingProps } from '..'; const lorem = `Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolores @@ -135,7 +135,7 @@ class PagingWithCustomComponent extends React.Component ( + (Story: () => JSX.Element) => (
@@ -146,95 +146,6 @@ export default { export const GoToAbsensePageStory: Story = () => ; GoToAbsensePageStory.storyName = 'GoToAbsensePage'; -GoToAbsensePageStory.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'hover' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { - in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], - tests: ['hover', 'Move to page by Ender'], - }, - flaky: { - in: ['firefox2022', 'firefox2022Dark'], - tests: ['Move focus right', 'Move to page by Ender'], - }, - }, - tests: { - async plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('plain'); - }, - async hover() { - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` }), - }) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('hover'); - }, - async 'change page by number'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('change page by number'); - }, - async 'change page by forwardLink'() { - // NOTE Firefox bug if click send right after click from previous test it results as double click - await delay(500); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: `[data-tid='Paging__forwardLink']` })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('change page by forwardLink'); - }, - async focused() { - // NOTE Firefox bug if click send right after click from previous test it results as double click - await delay(500); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('focused'); - }, - async 'Move focus right'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` })) - .pause(100) - .sendKeys(this.keys.ARROW_RIGHT) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('Move focus right'); - }, - async 'Move to page by Ender'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: `[data-tid='Paging__pageLinkWrapper']` })) - .pause(100) - .sendKeys(this.keys.ARROW_RIGHT) - .pause(100) - .sendKeys(this.keys.ENTER) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('Move to page by Ender'); - }, - }, - }, -}; - export const SimpleSamples = () => ( <> diff --git a/packages/react-ui/components/Paging/__tests__/Paging-test.tsx b/packages/react-ui/components/Paging/__tests__/Paging-test.tsx index 56f245f2e28..2e60c2ab9f0 100644 --- a/packages/react-ui/components/Paging/__tests__/Paging-test.tsx +++ b/packages/react-ui/components/Paging/__tests__/Paging-test.tsx @@ -9,10 +9,10 @@ import { PagingLocaleHelper } from '../locale'; import { Paging, PagingDataTids } from '../Paging'; describe('Paging', () => { - it('should keep focus on body when the component is disabled', () => { + it('should keep focus on body when the component is disabled', async () => { render(); - userEvent.tab(); + await userEvent.tab(); expect(document.body).toHaveFocus(); }); diff --git a/packages/react-ui/components/PasswordInput/ClosedIcon.tsx b/packages/react-ui/components/PasswordInput/ClosedIcon.tsx index 654afcca696..8c6048f03fa 100644 --- a/packages/react-ui/components/PasswordInput/ClosedIcon.tsx +++ b/packages/react-ui/components/PasswordInput/ClosedIcon.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/display-name */ import React from 'react'; import { iconSizer } from '../../internal/icons2022/iconSizer'; diff --git a/packages/react-ui/components/PasswordInput/OpenedIcon.tsx b/packages/react-ui/components/PasswordInput/OpenedIcon.tsx index 48ef4c14e0a..c927db4a1f9 100644 --- a/packages/react-ui/components/PasswordInput/OpenedIcon.tsx +++ b/packages/react-ui/components/PasswordInput/OpenedIcon.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/display-name */ import React from 'react'; import { iconSizer } from '../../internal/icons2022/iconSizer'; diff --git a/packages/react-ui/components/PasswordInput/PasswordInput.tsx b/packages/react-ui/components/PasswordInput/PasswordInput.tsx index fd6cd9713b9..5bc3a98bc58 100644 --- a/packages/react-ui/components/PasswordInput/PasswordInput.tsx +++ b/packages/react-ui/components/PasswordInput/PasswordInput.tsx @@ -1,5 +1,3 @@ -// TODO: Enable this rule in functional components. -/* eslint-disable @typescript-eslint/no-unused-vars */ import React, { AriaAttributes } from 'react'; import PropTypes from 'prop-types'; import { globalObject, isBrowser } from '@skbkontur/global-object'; @@ -102,7 +100,7 @@ export class PasswordInput extends React.PureComponent - {this.renderMain} + {this.renderMain(this.props)} ); }} diff --git a/packages/react-ui/components/PasswordInput/__creevey__/PasswordInput.creevey.ts b/packages/react-ui/components/PasswordInput/__creevey__/PasswordInput.creevey.ts new file mode 100644 index 00000000000..a8634f0cb12 --- /dev/null +++ b/packages/react-ui/components/PasswordInput/__creevey__/PasswordInput.creevey.ts @@ -0,0 +1,43 @@ +import { story, kind, test } from 'creevey'; + +kind('PasswordInput', () => { + story('Plain', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + // TODO @Khlutkova fix after update browsers + 'story-skip-0': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['With visible password'], + }, + 'flickering screenshot': { in: ['chrome2022'], tests: ['With typed password'] }, + }, + }); + + test('Plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); + }); + + test('With typed password', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[type="password"]' })) + .sendKeys('Test...') + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('With typed password'); + }); + + test('With visible password', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[type="password"]' })) + .sendKeys('Test...') + .click(this.browser.findElement({ css: '[data-tid="PasswordInputEyeIcon"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('With visible password'); + }); + }); +}); diff --git a/packages/react-ui/components/PasswordInput/__stories__/PasswordInput.stories.tsx b/packages/react-ui/components/PasswordInput/__stories__/PasswordInput.stories.tsx index 7f41ff4e785..59fe20c0e5a 100644 --- a/packages/react-ui/components/PasswordInput/__stories__/PasswordInput.stories.tsx +++ b/packages/react-ui/components/PasswordInput/__stories__/PasswordInput.stories.tsx @@ -49,40 +49,5 @@ class Component extends React.Component { export default { title: 'PasswordInput' }; export const Plain: Story = () => ; -Plain.parameters = { - creevey: { - skip: { - // TODO @Khlutkova fix after update browsers - 'story-skip-0': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['With visible password'] }, - 'flickering screenshot': { in: ['chrome2022'], tests: ['With typed password'] }, - }, - tests: { - async Plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); - }, - async 'With typed password'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[type="password"]' })) - .sendKeys('Test...') - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('With typed password'); - }, - async 'With visible password'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[type="password"]' })) - .sendKeys('Test...') - .click(this.browser.findElement({ css: '[data-tid="PasswordInputEyeIcon"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('With visible password'); - }, - }, - }, -}; export const CapsLockLabel = () => ; CapsLockLabel.storyName = 'CapsLock label'; diff --git a/packages/react-ui/components/PasswordInput/__tests__/PasswordInput-test.tsx b/packages/react-ui/components/PasswordInput/__tests__/PasswordInput-test.tsx index 0eb8368127f..9ea0d7c3b3f 100644 --- a/packages/react-ui/components/PasswordInput/__tests__/PasswordInput-test.tsx +++ b/packages/react-ui/components/PasswordInput/__tests__/PasswordInput-test.tsx @@ -9,20 +9,20 @@ import { componentsLocales as PasswordInputLocaleEn } from '../locale/locales/en import { componentsLocales as PasswordInputLocaleRu } from '../locale/locales/ru'; describe('PasswordInput', () => { - it('should change icon after clicking on the toggle button', () => { + it('should change icon after clicking on the toggle button', async () => { render(); const toggleButton = screen.getByTestId(PasswordInputDataTids.eyeIcon); const toggleButtonInitialIcon = toggleButton.innerHTML; - userEvent.click(toggleButton); + await userEvent.click(toggleButton); const toggleButtonUpdatedIcon = toggleButton.innerHTML; expect(toggleButtonInitialIcon).not.toBe(toggleButtonUpdatedIcon); }); - it('should change input type after clicking on the toggle button', () => { + it('should change input type after clicking on the toggle button', async () => { const inputValue = 'input'; render(); @@ -33,7 +33,7 @@ describe('PasswordInput', () => { expect(input).toHaveAttribute('type', 'password'); const toggleButton = screen.getByTestId(PasswordInputDataTids.eyeIcon); - userEvent.click(toggleButton); + await userEvent.click(toggleButton); // After clicking on the toggle button input should have type `text` expect(input).toHaveAttribute('type', 'text'); @@ -52,7 +52,7 @@ describe('PasswordInput', () => { expect(component.find(`[data-tid~="PasswordInputCapsLockDetector"]`)).toHaveLength(0); }); - it('should focus on the input after clicking on the toggle button', () => { + it('should focus on the input after clicking on the toggle button', async () => { const inputValue = 'input'; render(); @@ -64,12 +64,12 @@ describe('PasswordInput', () => { // Input should have type `password` at the moment expect(input).not.toHaveFocus(); - userEvent.click(toggleButton); + await userEvent.click(toggleButton); // After clicking on the toggle button input should get focus // Input should have type `text` at the moment expect(input).toHaveFocus(); - userEvent.click(toggleButton); + await userEvent.click(toggleButton); // After re-clicking on the toggle button input should get focus again // Input should have type `password` at the moment expect(input).toHaveFocus(); @@ -98,24 +98,24 @@ describe('PasswordInput', () => { expect(screen.queryByDisplayValue(inputValue)).not.toHaveFocus(); }); - it('handels onKeyPress event', () => { + it('handels onKeyPress event', async () => { const onKeyPress = jest.fn(); const inputValue = 'input'; render(); - userEvent.type(screen.getByDisplayValue(inputValue), '{enter}'); + await userEvent.type(screen.getByDisplayValue(inputValue), '{enter}'); expect(onKeyPress).toHaveBeenCalledTimes(1); }); - it('handels onKeyDown event', () => { + it('handels onKeyDown event', async () => { const onKeyDown = jest.fn(); const inputValue = 'input'; render(); - userEvent.type(screen.getByDisplayValue(inputValue), '{enter}'); + await userEvent.type(screen.getByDisplayValue(inputValue), '{enter}'); expect(onKeyDown).toHaveBeenCalledTimes(1); }); @@ -125,14 +125,14 @@ describe('PasswordInput', () => { expect(screen.queryByTestId(PasswordInputDataTids.eyeIcon)).not.toBeInTheDocument(); }); - it('should hide symbols on click outside', () => { + it('should hide symbols on click outside', async () => { const inputValue = 'input'; render(); - userEvent.click(screen.getByTestId(PasswordInputDataTids.eyeIcon)); + await userEvent.click(screen.getByTestId(PasswordInputDataTids.eyeIcon)); expect(screen.getByDisplayValue(inputValue)).toHaveAttribute('type', 'text'); - userEvent.click(document.body); + await userEvent.click(document.body); expect(screen.getByDisplayValue(inputValue)).toHaveAttribute('type', 'password'); }); @@ -143,27 +143,27 @@ describe('PasswordInput', () => { }); describe('a11y', () => { - it('sets value for aria-label attribute', () => { + it('sets value for aria-label attribute', async () => { const ariaLabel = 'aria-label'; render(); // Clicking on the eye icon to turn input from password to text - userEvent.click(screen.getByTestId(PasswordInputDataTids.eyeIcon)); + await userEvent.click(screen.getByTestId(PasswordInputDataTids.eyeIcon)); expect(screen.getByRole('textbox')).toHaveAttribute('aria-label', ariaLabel); }); - it('eye icon has correct aria-label attribute (ru)', () => { + it('eye icon has correct aria-label attribute (ru)', async () => { render(); expect(screen.getByRole('button')).toHaveAttribute('aria-label', PasswordInputLocaleRu.eyeOpenedAriaLabel); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(screen.getByRole('button')).toHaveAttribute('aria-label', PasswordInputLocaleRu.eyeClosedAriaLabel); }); - it('eye icon has correct aria-label attribute (en)', () => { + it('eye icon has correct aria-label attribute (en)', async () => { render( @@ -172,7 +172,7 @@ describe('PasswordInput', () => { expect(screen.getByRole('button')).toHaveAttribute('aria-label', PasswordInputLocaleEn.eyeOpenedAriaLabel); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(screen.getByRole('button')).toHaveAttribute('aria-label', PasswordInputLocaleEn.eyeClosedAriaLabel); }); @@ -188,7 +188,7 @@ describe('PasswordInput', () => { expect(screen.getByRole('button')).toHaveAttribute('aria-label', customAriaLabel); }); - it('sets custom value for `eyeClosedAriaLabel` locale', () => { + it('sets custom value for `eyeClosedAriaLabel` locale', async () => { const customAriaLabel = 'test'; render( @@ -196,7 +196,7 @@ describe('PasswordInput', () => { , ); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(screen.getByRole('button')).toHaveAttribute('aria-label', customAriaLabel); }); diff --git a/packages/react-ui/components/Radio/Radio.tsx b/packages/react-ui/components/Radio/Radio.tsx index c98ee65205d..8aca4a59d8d 100644 --- a/packages/react-ui/components/Radio/Radio.tsx +++ b/packages/react-ui/components/Radio/Radio.tsx @@ -1,5 +1,3 @@ -// TODO: Enable this rule in functional components. -/* eslint-disable @typescript-eslint/no-unused-vars */ import React, { AriaAttributes } from 'react'; import { globalObject } from '@skbkontur/global-object'; @@ -146,7 +144,7 @@ export class Radio extends React.Component, RadioState> { {(theme) => { this.theme = theme; return ( - + {this.renderMain} ); diff --git a/packages/react-ui/components/Radio/__creevey__/Radio.creevey.ts b/packages/react-ui/components/Radio/__creevey__/Radio.creevey.ts new file mode 100644 index 00000000000..eebbd8e3ec2 --- /dev/null +++ b/packages/react-ui/components/Radio/__creevey__/Radio.creevey.ts @@ -0,0 +1,27 @@ +import { story, kind, test } from 'creevey'; + +kind('Radio', () => { + story('Highlighted', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + flaky: { in: /firefox/ }, + }, + }); + + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('tabPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'body' })) + .sendKeys(this.keys.TAB) + .pause(500) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); + }); + }); +}); diff --git a/packages/react-ui/components/Radio/__stories__/Radio.stories.tsx b/packages/react-ui/components/Radio/__stories__/Radio.stories.tsx index d5eaff7ae2a..db8bf36027f 100644 --- a/packages/react-ui/components/Radio/__stories__/Radio.stories.tsx +++ b/packages/react-ui/components/Radio/__stories__/Radio.stories.tsx @@ -85,30 +85,6 @@ export const Highlighted: Story = () => { ); }; -Highlighted.parameters = { - creevey: { - skip: { - flaky: { in: /firefox/ }, - }, - tests: { - async plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('plain'); - }, - async tabPress() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: 'body' })) - .sendKeys(this.keys.TAB) - .pause(500) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); - }, - }, - }, -}; - export const Size: Story = () => { return (
diff --git a/packages/react-ui/components/Radio/__tests__/Radio-test.tsx b/packages/react-ui/components/Radio/__tests__/Radio-test.tsx index b063cfb015b..12583de0895 100644 --- a/packages/react-ui/components/Radio/__tests__/Radio-test.tsx +++ b/packages/react-ui/components/Radio/__tests__/Radio-test.tsx @@ -48,18 +48,18 @@ describe('Radio', () => { expect(onFocus).toHaveBeenCalledTimes(1); }); - it('should handle onValueChange event', () => { + it('should handle onValueChange event', async () => { const onValueChange = jest.fn(); const radioRef = React.createRef>(); render(); - userEvent.click(screen.getByRole('radio')); + await userEvent.click(screen.getByRole('radio')); expect(onValueChange).toHaveBeenCalledTimes(1); }); - it('should focus by tab pressing', () => { + it('should focus by tab pressing', async () => { render(); - userEvent.tab(); + await userEvent.tab(); expect(screen.getByRole('radio')).toHaveFocus(); }); @@ -80,7 +80,7 @@ describe('Radio', () => { expect(screen.getByRole('radio')).not.toHaveFocus(); }); - it('should check radio in RadioGroup', () => { + it('should check radio in RadioGroup', async () => { render( @@ -89,7 +89,7 @@ describe('Radio', () => { ); const radios = screen.getAllByRole('radio'); - userEvent.click(radios[0]); + await userEvent.click(radios[0]); expect(screen.getAllByRole('radio')[0]).toBeChecked(); }); }); diff --git a/packages/react-ui/components/RadioGroup/RadioGroup.tsx b/packages/react-ui/components/RadioGroup/RadioGroup.tsx index 39dea76ef6a..5014e4b593a 100644 --- a/packages/react-ui/components/RadioGroup/RadioGroup.tsx +++ b/packages/react-ui/components/RadioGroup/RadioGroup.tsx @@ -276,7 +276,7 @@ function mapItems( function normalizeEntry(entry: T | [T, React.ReactNode]): [T, React.ReactNode] { if (!Array.isArray(entry)) { - return [entry, entry]; + return [entry, entry as unknown as React.ReactNode]; } return entry; } diff --git a/packages/react-ui/components/RadioGroup/__creevey__/RadioGroup.creevey.ts b/packages/react-ui/components/RadioGroup/__creevey__/RadioGroup.creevey.ts new file mode 100644 index 00000000000..e43ca3cff3a --- /dev/null +++ b/packages/react-ui/components/RadioGroup/__creevey__/RadioGroup.creevey.ts @@ -0,0 +1,85 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('RadioGroup', () => { + story('Vertical', ({ setStoryParameters }) => { + setStoryParameters({ + captureElement: '#RadioGroup-wrap', + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'hovered' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hovered', 'clicked'] }, + }, + }); + + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('hovered', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: '[data-comp-name~="RadioGroup"] > span > label' }), + }) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); + }); + + test('clicked', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="RadioGroup"] > span > label' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); + }); + + test('mouseLeave', async function () { + // NOTE Firefox bug if click send right after click from previous test it results as double click + await delay(500); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="RadioGroup"] > span > label' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="JustButton"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('mouseLeave'); + }); + + test('tabPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="JustButton"]' })) + .sendKeys(this.keys.TAB) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); + }); + + test('arrow_down', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="JustButton"]' })) + .sendKeys(this.keys.TAB) + .pause(100) + .sendKeys(this.keys.DOWN) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('arrow_down'); + }); + }); +}); diff --git a/packages/react-ui/components/RadioGroup/__stories__/RadioGroup.stories.tsx b/packages/react-ui/components/RadioGroup/__stories__/RadioGroup.stories.tsx index f46551cddf4..cac414d5b4d 100644 --- a/packages/react-ui/components/RadioGroup/__stories__/RadioGroup.stories.tsx +++ b/packages/react-ui/components/RadioGroup/__stories__/RadioGroup.stories.tsx @@ -6,7 +6,6 @@ import { Radio } from '../../Radio'; import { Gapped } from '../../Gapped'; import { Button } from '../../Button'; import { Nullable } from '../../../typings/utility-types'; -import { delay } from '../../../lib/utils'; import { RadioGroupProps } from '..'; interface ComponentState { @@ -56,82 +55,6 @@ export const Vertical: Story = () => { }; Vertical.storyName = 'vertical'; -Vertical.parameters = { - creevey: { - captureElement: '#RadioGroup-wrap', - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'hovered' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['hovered', 'clicked'] }, - }, - tests: { - async plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('plain'); - }, - async hovered() { - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: '[data-comp-name~="RadioGroup"] > span > label' }), - }) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); - }, - async clicked() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="RadioGroup"] > span > label' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); - }, - async mouseLeave() { - // NOTE Firefox bug if click send right after click from previous test it results as double click - await delay(500); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="RadioGroup"] > span > label' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="JustButton"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('mouseLeave'); - }, - async tabPress() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="JustButton"]' })) - .sendKeys(this.keys.TAB) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); - }, - async arrow_down() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="JustButton"]' })) - .sendKeys(this.keys.TAB) - .pause(100) - .sendKeys(this.keys.DOWN) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('arrow_down'); - }, - }, - }, -}; - export const Inline = () => ; Inline.storyName = 'inline'; diff --git a/packages/react-ui/components/RadioGroup/__tests__/RadioGroup-test.tsx b/packages/react-ui/components/RadioGroup/__tests__/RadioGroup-test.tsx index 42e97074585..f5dcf816488 100644 --- a/packages/react-ui/components/RadioGroup/__tests__/RadioGroup-test.tsx +++ b/packages/react-ui/components/RadioGroup/__tests__/RadioGroup-test.tsx @@ -37,7 +37,6 @@ describe('', () => { const radios = screen.getAllByRole('radio'); items.forEach((item, index) => { - // eslint-disable-next-line jest-dom/prefer-to-have-value expect(radios[index]).toHaveAttribute('value', item); }); }); @@ -52,20 +51,20 @@ describe('', () => { }); }); - it('checks radio on click', () => { + it('checks radio on click', async () => { renderRadioGroup({ items }); const radios = screen.getAllByTestId(RadioDataTids.root); - userEvent.click(radios[clickedIndex]); + await userEvent.click(radios[clickedIndex]); expect(screen.getAllByRole('radio')[clickedIndex]).toBeChecked(); }); - it('calls onValueChange on radio click', () => { + it('calls onValueChange on radio click', async () => { const onValueChange = jest.fn(); renderRadioGroup({ items, onValueChange }); const radios = screen.getAllByTestId(RadioDataTids.root); - userEvent.click(radios[clickedIndex]); + await userEvent.click(radios[clickedIndex]); expect(onValueChange).toHaveBeenCalled(); const [value] = onValueChange.mock.calls[0]; @@ -122,7 +121,7 @@ describe('', () => { expect(screen.getByTestId('myDupaComponent')).toBeInTheDocument(); }); - it('checks children radio on click', () => { + it('checks children radio on click', async () => { const children = (
Hello @@ -133,11 +132,11 @@ describe('', () => { renderRadioGroup({ children }); const radios = screen.getAllByRole('radio'); - userEvent.click(radios[clickedIndex]); + await userEvent.click(radios[clickedIndex]); expect(screen.getAllByRole('radio')[clickedIndex]).toBeChecked(); }); - it('calls onValueChange on children radio click', () => { + it('calls onValueChange on children radio click', async () => { const children = (
Hello @@ -149,7 +148,7 @@ describe('', () => { renderRadioGroup({ children, onValueChange }); const radios = screen.getAllByRole('radio'); - userEvent.click(radios[clickedIndex]); + await userEvent.click(radios[clickedIndex]); expect(onValueChange).toHaveBeenCalled(); const [value] = onValueChange.mock.calls[0]; @@ -214,12 +213,12 @@ describe('', () => { expect(RadioGroup.Prevent).toBeDefined(); }); - it('works with number values', () => { + it('works with number values', async () => { const items = [1, 2, 3, 4]; renderRadioGroup({ items }); const radios = screen.getAllByRole('radio'); - userEvent.click(radios[clickedIndex]); + await userEvent.click(radios[clickedIndex]); expect(screen.getAllByRole('radio')[clickedIndex]).toBeChecked(); }); @@ -237,7 +236,7 @@ describe('', () => { expect(onBlur).toHaveBeenCalledTimes(1); }); - it('should call `onBlur` after click outside of radio group', () => { + it('should call `onBlur` after click outside of radio group', async () => { const onBlur = jest.fn(); const onRadioBlur = jest.fn(); @@ -249,7 +248,7 @@ describe('', () => { ); const radioOne = screen.getAllByRole('radio')[0]; const radioTwo = screen.getAllByRole('radio')[1]; - userEvent.click(radioOne); + await userEvent.click(radioOne); fireEvent.blur(radioOne); fireEvent.blur(radioTwo); diff --git a/packages/react-ui/components/ScrollContainer/__creevey__/ScrollContainer.creevey.ts b/packages/react-ui/components/ScrollContainer/__creevey__/ScrollContainer.creevey.ts new file mode 100644 index 00000000000..67aadd5455c --- /dev/null +++ b/packages/react-ui/components/ScrollContainer/__creevey__/ScrollContainer.creevey.ts @@ -0,0 +1,271 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('ScrollContainer', () => { + story('WithDynamicContent', ({ setStoryParameters }) => { + setStoryParameters({ captureElement: '#test-container' }); + + test('changeContent', async function () { + const idle = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#add' })) + .perform(); + const addContent = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scroll50' })) + .perform(); + const scroll50 = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scroll100' })) + .perform(); + const scroll100 = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#remove' })) + .perform(); + const removeContent = await this.takeScreenshot(); + await this.expect({ idle, addContent, scroll50, scroll100, removeContent }).to.matchImages(); + }); + }); + + story('WithOnlyCustomHorizontalScroll', ({ setStoryParameters }) => { + setStoryParameters({ captureElement: '#test-container' }); + + test('moveScroll', async function () { + const idle = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scroll50' })) + .perform(); + const scroll50 = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scroll100' })) + .perform(); + const scroll100 = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scroll0' })) + .perform(); + const scroll0 = await this.takeScreenshot(); + await this.expect({ idle, scroll50, scroll100, scroll0 }).to.matchImages(); + }); + + test('changeContent', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#add' })) + .perform(); + const addContent = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scroll50' })) + .perform(); + const scroll50 = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scroll100' })) + .perform(); + const scroll100 = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scroll0' })) + .perform(); + const scroll0 = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#remove' })) + .perform(); + const removeContent = await this.takeScreenshot(); + await this.expect({ addContent, scroll50, scroll100, scroll0, removeContent }).to.matchImages(); + }); + }); + + story('WithScrollTo', ({ setStoryParameters }) => { + setStoryParameters({ captureElement: '#test-container' }); + + test('scrollTo', async function () { + const idle = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scrollTo' })) + .perform(); + const scrollTo = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scrollToTop' })) + .perform(); + const scrollToTop = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scrollToLeft' })) + .perform(); + const scrollToLeft = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scrollToBottom' })) + .perform(); + const scrollToBottom = await this.takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#scrollToRight' })) + .perform(); + const scrollToRight = await this.takeScreenshot(); + await this.expect({ + idle, + scrollTo, + scrollToTop, + scrollToBottom, + scrollToLeft, + scrollToRight, + }).to.matchImages(); + }); + }); + + story('HideScrollBar', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\b(firefox|chrome)\b)/ } } }); + + test('hideScroll', async function () { + const beforeScroll = await this.takeScreenshot(); + await this.browser.executeScript(function () { + const scrollContainer = window.document.querySelector('[data-tid~="ScrollContainer__inner"]'); + if (scrollContainer) { + scrollContainer.scrollTop = 500; + } + }); + this.browser + .actions({ + bridge: true, + }) + .move({ origin: this.browser.findElement({ css: 'body' }) }); + await delay(200); + const duringScroll = await this.takeScreenshot(); + await delay(3000); + const afterScroll = await this.takeScreenshot(); + await this.expect({ beforeScroll, duringScroll, afterScroll }).to.matchImages(); + }); + }); + + story('ScrollBarVisibleAfterTogglingDisabled', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }); + + test('toggleDisabled', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="disable-button"]' })) + .click(this.browser.findElement({ css: '[data-tid="disable-button"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('toggleDisabled'); + }); + }); + + story('ShowScrollBarOnScroll', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'themes dont affect logic': { in: /^(?!\b(firefox|chrome)\b)/ } } }); + + test('hideScroll', async function () { + const beforeScroll = await this.takeScreenshot(); + await this.browser.executeScript(function () { + const scrollContainer = window.document.querySelector('[data-tid~="ScrollContainer__inner"]'); + if (scrollContainer) { + scrollContainer.scrollTop = 500; + } + }); + this.browser + .actions({ + bridge: true, + }) + .move({ origin: this.browser.findElement({ css: 'body' }) }); + await delay(200); + const duringScroll = await this.takeScreenshot(); + await delay(3000); + const afterScroll = await this.takeScreenshot(); + await this.expect({ beforeScroll, duringScroll, afterScroll }).to.matchImages(); + }); + }); + + story('ShowScrollBarOnHover', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'hover works only in firefox': { in: /^(?!\b(firefox)\b)/ } } }); + + test('hideScroll', async function () { + this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: '[data-tid~="ScrollContainer__root"]' }), + }) + .perform(); + await delay(500); + const hovered = await this.takeScreenshot(); + this.browser + .actions({ + bridge: true, + }) + .move({ x: 1000, y: 700 }) + .perform(); + await delay(3000); + const withoutHover = await this.takeScreenshot(); + await this.expect({ hovered, withoutHover }).to.matchImages(); + }); + }); + story('NeverShowScrollBar', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'themes dont affect logic': { in: /^(?!\b(firefox|chrome)\b)/ } }, + }); + }); + story('OffsetY', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, + }); + }); + story('OffsetX', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, + }); + }); + story('OffsetYAndX', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, + }); + }); +}); diff --git a/packages/react-ui/components/ScrollContainer/__stories__/ScrollContainer.stories.tsx b/packages/react-ui/components/ScrollContainer/__stories__/ScrollContainer.stories.tsx index 13f3acc5de3..36a32e1bbe1 100644 --- a/packages/react-ui/components/ScrollContainer/__stories__/ScrollContainer.stories.tsx +++ b/packages/react-ui/components/ScrollContainer/__stories__/ScrollContainer.stories.tsx @@ -11,7 +11,6 @@ import { import { Story } from '../../../typings/stories'; import { Gapped } from '../../Gapped'; import { ThemeContext } from '../../../lib/theming/ThemeContext'; -import { delay } from '../../../lib/utils'; function getItems(count: number) { const items = []; @@ -27,14 +26,16 @@ const wrapperStyle = { border: '1px solid #000', }; -const DynamicContent: React.FC<{ - state: ScrollContainerScrollStateY | ScrollContainerScrollStateX; - scroll: (percentage: number) => void; - add: () => void; - remove: () => void; - onChangeScrollYState?: (x: ScrollContainerScrollStateY) => void; - onChangeScrollXState?: (x: ScrollContainerScrollStateX) => void; -}> = ({ children, state, scroll, add, remove, onChangeScrollXState, onChangeScrollYState }) => { +const DynamicContent: React.FC< + React.PropsWithChildren<{ + state: ScrollContainerScrollStateY | ScrollContainerScrollStateX; + scroll: (percentage: number) => void; + add: () => void; + remove: () => void; + onChangeScrollYState?: (x: ScrollContainerScrollStateY) => void; + onChangeScrollXState?: (x: ScrollContainerScrollStateX) => void; + }> +> = ({ children, state, scroll, add, remove, onChangeScrollXState, onChangeScrollYState }) => { return (
@@ -187,50 +188,6 @@ export const WithDynamicContent: Story = () => { ); }; -WithDynamicContent.parameters = { - creevey: { - captureElement: '#test-container', - tests: { - async changeContent() { - const idle = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#add' })) - .perform(); - const addContent = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scroll50' })) - .perform(); - const scroll50 = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scroll100' })) - .perform(); - const scroll100 = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#remove' })) - .perform(); - const removeContent = await this.takeScreenshot(); - - await this.expect({ idle, addContent, scroll50, scroll100, removeContent }).to.matchImages(); - }, - }, - }, -}; export const WithOnlyCustomHorizontalScroll: Story = () => { const [state, setState] = React.useState('left'); @@ -258,86 +215,6 @@ export const WithOnlyCustomHorizontalScroll: Story = () => { }; WithOnlyCustomHorizontalScroll.storyName = 'with only custom horizontal scroll'; -WithOnlyCustomHorizontalScroll.parameters = { - creevey: { - captureElement: '#test-container', - tests: { - async moveScroll() { - const idle = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scroll50' })) - .perform(); - const scroll50 = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scroll100' })) - .perform(); - const scroll100 = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scroll0' })) - .perform(); - const scroll0 = await this.takeScreenshot(); - - await this.expect({ idle, scroll50, scroll100, scroll0 }).to.matchImages(); - }, - - async changeContent() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#add' })) - .perform(); - const addContent = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scroll50' })) - .perform(); - const scroll50 = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scroll100' })) - .perform(); - const scroll100 = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scroll0' })) - .perform(); - const scroll0 = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#remove' })) - .perform(); - const removeContent = await this.takeScreenshot(); - - await this.expect({ addContent, scroll50, scroll100, scroll0, removeContent }).to.matchImages(); - }, - }, - }, -}; export const WithScrollTo: Story = () => { const refScrollContainer = React.useRef(null); @@ -387,66 +264,6 @@ export const WithScrollTo: Story = () => { ); }; -WithScrollTo.parameters = { - creevey: { - captureElement: '#test-container', - tests: { - async scrollTo() { - const idle = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scrollTo' })) - .perform(); - const scrollTo = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scrollToTop' })) - .perform(); - const scrollToTop = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scrollToLeft' })) - .perform(); - const scrollToLeft = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scrollToBottom' })) - .perform(); - const scrollToBottom = await this.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#scrollToRight' })) - .perform(); - const scrollToRight = await this.takeScreenshot(); - - await this.expect({ - idle, - scrollTo, - scrollToTop, - scrollToBottom, - scrollToLeft, - scrollToRight, - }).to.matchImages(); - }, - }, - }, -}; - export const OffsetY: Story = () => (
(
); -OffsetY.parameters = { - creevey: { skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }, -}; export const OffsetX = () => (
@@ -489,10 +303,6 @@ export const OffsetX = () => (
); -OffsetX.parameters = { - creevey: { skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }, -}; - export const OffsetYAndX: Story = () => (
(
); -OffsetYAndX.parameters = { - creevey: { skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } } }, -}; export const HideScrollBar: Story = () => (
@@ -541,32 +348,6 @@ export const HideScrollBar: Story = () => (
); -HideScrollBar.parameters = { - creevey: { - skip: { 'themes dont affect logic': { in: /^(?!\b(firefox|chrome)\b)/ } }, - tests: { - async hideScroll() { - const beforeScroll = await this.takeScreenshot(); - await this.browser.executeScript(function () { - const scrollContainer = window.document.querySelector('[data-tid~="ScrollContainer__inner"]'); - if (scrollContainer) { - scrollContainer.scrollTop = 500; - } - }); - this.browser - .actions({ - bridge: true, - }) - .move({ origin: this.browser.findElement({ css: 'body' }) }); - await delay(200); - const duringScroll = await this.takeScreenshot(); - await delay(3000); - const afterScroll = await this.takeScreenshot(); - await this.expect({ beforeScroll, duringScroll, afterScroll }).to.matchImages(); - }, - }, - }, -}; export const ScrollBarVisibleAfterTogglingDisabled: Story = () => { const [isDisabled, setIsDisabled] = useState(false); @@ -592,24 +373,6 @@ export const ScrollBarVisibleAfterTogglingDisabled: Story = () => { }; ScrollBarVisibleAfterTogglingDisabled.storyName = 'scroll bar visible after toggling disabled'; -ScrollBarVisibleAfterTogglingDisabled.parameters = { - creevey: { - skip: { 'themes dont affect logic': { in: /^(?!\bchrome\b)/ } }, - tests: { - async toggleDisabled() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="disable-button"]' })) - .click(this.browser.findElement({ css: '[data-tid="disable-button"]' })) - .perform(); - - await this.expect(await this.takeScreenshot()).to.matchImage('toggleDisabled'); - }, - }, - }, -}; export const ShowScrollBarOnScroll: Story = () => (
@@ -631,32 +394,6 @@ export const ShowScrollBarOnScroll: Story = () => (
); -ShowScrollBarOnScroll.parameters = { - creevey: { - skip: { 'themes dont affect logic': { in: /^(?!\b(firefox|chrome)\b)/ } }, - tests: { - async hideScroll() { - const beforeScroll = await this.takeScreenshot(); - await this.browser.executeScript(function () { - const scrollContainer = window.document.querySelector('[data-tid~="ScrollContainer__inner"]'); - if (scrollContainer) { - scrollContainer.scrollTop = 500; - } - }); - this.browser - .actions({ - bridge: true, - }) - .move({ origin: this.browser.findElement({ css: 'body' }) }); - await delay(200); - const duringScroll = await this.takeScreenshot(); - await delay(3000); - const afterScroll = await this.takeScreenshot(); - await this.expect({ beforeScroll, duringScroll, afterScroll }).to.matchImages(); - }, - }, - }, -}; export const ShowScrollBarOnHover: Story = () => (
@@ -678,34 +415,6 @@ export const ShowScrollBarOnHover: Story = () => (
); -ShowScrollBarOnHover.parameters = { - creevey: { - skip: { 'hover works only in firefox': { in: /^(?!\b(firefox)\b)/ } }, - tests: { - async hideScroll() { - this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: '[data-tid~="ScrollContainer__root"]' }), - }) - .perform(); - await delay(500); - const hovered = await this.takeScreenshot(); - this.browser - .actions({ - bridge: true, - }) - .move({ x: 1000, y: 700 }) - .perform(); - await delay(3000); - const withoutHover = await this.takeScreenshot(); - await this.expect({ hovered, withoutHover }).to.matchImages(); - }, - }, - }, -}; export const NeverShowScrollBar: Story = () => (
@@ -722,8 +431,3 @@ export const NeverShowScrollBar: Story = () => (
); -NeverShowScrollBar.parameters = { - creevey: { - skip: { 'themes dont affect logic': { in: /^(?!\b(firefox|chrome)\b)/ } }, - }, -}; diff --git a/packages/react-ui/components/Select/ArrowDownIcon.tsx b/packages/react-ui/components/Select/ArrowDownIcon.tsx index 0d0f4c9ab06..799cc42af46 100644 --- a/packages/react-ui/components/Select/ArrowDownIcon.tsx +++ b/packages/react-ui/components/Select/ArrowDownIcon.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/display-name */ import React from 'react'; import { ArrowCDownIcon16Regular } from '../../internal/icons2022/ArrowCDownIcon/ArrowCDownIcon16Regular'; diff --git a/packages/react-ui/components/Select/Select.md b/packages/react-ui/components/Select/Select.md index cd454d0a44e..1fc34b83825 100644 --- a/packages/react-ui/components/Select/Select.md +++ b/packages/react-ui/components/Select/Select.md @@ -3,9 +3,10 @@ ```jsx harmony const [value, setValue] = React.useState(); -const items = [Select.static(() => Not selectable), 'One', 'Two', 'Three', Select.SEP, 'Four']; +const items = [Select.staticElement(() => Not + selectable), 'One', 'Two', 'Three', Select.SEP, 'Four']; -; ``` @@ -47,17 +48,18 @@ const items = ['One', 'Two', 'Three', Select.SEP, 'Four']; Пример использования пропа `_renderButton`: ```jsx harmony -import { Link } from '@skbkontur/react-ui'; +import {Link} from '@skbkontur/react-ui'; import PeopleIcon from '@skbkontur/react-icons/People'; const [value, setValue] = React.useState(); -const items = [Select.static(() => Not selectable), 'One', 'Two', 'Three', Select.SEP, 'Four']; +const items = [Select.staticElement(() => Not + selectable), 'One', 'Two', 'Three', Select.SEP, 'Four']; const renderLinkButton = params => { const linkProps = { disabled: params.disabled, - icon: , + icon: , _button: true, _buttonOpened: params.opened, diff --git a/packages/react-ui/components/Select/Select.tsx b/packages/react-ui/components/Select/Select.tsx index 30372eafef3..6d40d32b1c8 100644 --- a/packages/react-ui/components/Select/Select.tsx +++ b/packages/react-ui/components/Select/Select.tsx @@ -122,7 +122,7 @@ export interface SelectProps * Вставить невыделяемый элемент со своей разметкой можно так: * ``` *
); -Simple.parameters = { - creevey: { - captureElement: '.dropdown-test-container', - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'MenuItem hover' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['MenuItem hover'] }, - }, - tests: selectTests, - }, -}; - export const MobileSimple = () => { const items = [ 'one', @@ -248,7 +174,7 @@ MobileSimple.parameters = { creevey: { skip: true }, }; MobileSimple.decorators = [ - (Story: Story) => ( + (Story: () => JSX.Element) => (
JSX.Element]; export const MobileWithTitle: Story = () => ( JSX.Element]; export const MobileWithoutTitleAndSearch: Story = () => ( ; UseLink.storyName = 'use link'; -UseLink.parameters = { - creevey: { - captureElement: '.dropdown-test-container', - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'MenuItem hover' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['MenuItem hover'] }, - }, - tests: selectTests, - }, -}; - export const UseLinkWithIcon: Story = () => ; WithTextOverflow.storyName = 'with text overflow'; -WithTextOverflow.parameters = { - creevey: { - captureElement: '.dropdown-test-container', - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'MenuItem hover' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], tests: ['MenuItem hover'] }, - }, - tests: selectTests, - }, -}; - export const ExternalFocus = () => { class Sample extends React.Component { private selectElem: Select | null = null; @@ -493,28 +368,6 @@ export const UsingOnKeyDown: Story = () => { }; UsingOnKeyDown.storyName = 'using onKeyDown'; -UsingOnKeyDown.parameters = { - creevey: { - tests: { - async 'press Enter'() { - const element = await this.browser.findElement({ css: '.dropdown-test-container' }); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .sendKeys(this.keys.ENTER) - .sendKeys(this.keys.ARROW_DOWN) - .sendKeys(this.keys.ENTER) - .perform(); - await delay(1000); - - await this.expect(await element.takeScreenshot()).to.matchImage('press Enter'); - }, - }, - }, -}; - export const WithSearchAndVariousWidth: Story = () => { let selectElem: Select | null = null; const [width, setWidth] = useState(); @@ -543,95 +396,6 @@ export const WithSearchAndVariousWidth: Story = () => { }; WithSearchAndVariousWidth.storyName = 'with search'; -WithSearchAndVariousWidth.parameters = { - creevey: { - captureElement: '#test-element', - skip: { - flaky: { in: ['chrome2022', 'chrome2022Dark'] }, - }, - tests: { - async search() { - const root = await this.browser.findElement({ css: '[data-tid="root"]' }); - const select = await this.browser.findElement({ css: '[data-comp-name~="Select"]' }); - - await this.browser - .actions({ - bridge: true, - }) - .click(select) - .pause(500) - .perform(); - - const plainSearch = await root.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.ARROW_DOWN) - .pause(500) - .perform(); - - const pressKeyDown = await root.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Input"]' })) - .sendKeys('test') - .pause(500) - .perform(); - - const fullFieldSearch = await root.takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(select) - .click(select) - .pause(500) - .perform(); - - const emptySearch = await root.takeScreenshot(); - - await this.expect({ plainSearch, pressKeyDown, fullFieldSearch, emptySearch }).to.matchImages(); - }, - - async 'and various width'() { - const root = await this.browser.findElement({ css: '[data-tid="root"]' }); - - await this.browser - .actions({ bridge: true }) - .click(await this.browser.findElement({ css: '[data-tid="w100px"]' })) - .pause(500) - .perform(); - - const w100px = await root.takeScreenshot(); - - await this.browser - .actions({ bridge: true }) - .click(await this.browser.findElement({ css: '[data-tid="w300px"]' })) - .pause(500) - .perform(); - - const w300px = await root.takeScreenshot(); - - await this.browser - .actions({ bridge: true }) - .click(await this.browser.findElement({ css: '[data-tid="w100prc"]' })) - .pause(500) - .perform(); - - const w100prc = await root.takeScreenshot(); - - await this.expect({ w100px, w300px, w100prc }).to.matchImages(); - }, - }, - }, -}; - export const WithMenuAlignAndVariousWidth: Story = () => { const widths: Array['width']> = [ undefined, @@ -669,23 +433,11 @@ export const WithMenuAlignAndVariousWidth: Story = () => {
); }; -WithMenuAlignAndVariousWidth.parameters = { - creevey: { - tests: { - async open() { - const root = await this.browser.findElement({ css: '#test-element' }); - await delay(1000); - - await this.expect(await root.takeScreenshot()).to.matchImage(); - }, - }, - }, -}; export default { title: 'Select', decorators: [ - (Story, context) => { + (Story: () => JSX.Element, context) => { if ( !/mobile/i.test(context.name) && ![WithMenuAlignAndVariousWidth, WithManualPosition].includes(context.originalStoryFn as Story) @@ -719,65 +471,6 @@ export const WithManualPosition: Story = () => { ); }; WithManualPosition.storyName = 'with manual position'; -WithManualPosition.parameters = { - creevey: { - skip: { 'no themes': { in: /^(?!\b(chrome|firefox)\b)/ } }, - tests: { - async 'opened top with portal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened top with portal'); - }, - async 'opened bottom with portal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom with portal'); - }, - async 'opened top without portal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="portal"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened top without portal'); - }, - async 'opened bottom without portal'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="portal"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-tid~="pos"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-comp-name~="Select"]' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('opened bottom without portal'); - }, - }, - }, -}; export const Size: Story = () => { const items = ['one', two, 'three']; @@ -826,21 +519,3 @@ export const Size: Story = () => {
); }; - -Size.parameters = { - creevey: { - tests: { - async ClickedAll() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="open-all"]' })) - .pause(500) - .perform(); - await delay(1000); - await this.expect(await this.takeScreenshot()).to.matchImage('ClickedAll'); - }, - }, - }, -}; diff --git a/packages/react-ui/components/Select/__tests__/Select-test.tsx b/packages/react-ui/components/Select/__tests__/Select-test.tsx index 3934229d355..e4f195b38fe 100644 --- a/packages/react-ui/components/Select/__tests__/Select-test.tsx +++ b/packages/react-ui/components/Select/__tests__/Select-test.tsx @@ -1,6 +1,6 @@ import React, { useState } from 'react'; import userEvent from '@testing-library/user-event'; -import { fireEvent, render, screen } from '@testing-library/react'; +import { act, fireEvent, render, screen } from '@testing-library/react'; import { MenuItemDataTids } from '../../MenuItem'; import { MenuDataTids } from '../../../internal/Menu'; @@ -10,8 +10,20 @@ import { LangCodes, LocaleContext } from '../../../lib/locale'; import { SelectLocaleHelper } from '../locale'; import { Select, SelectDataTids, SelectIds } from '../Select'; +const itemsObject = { + first: 'One', + second: 'Not selectable', + third: 'Two', + fourth: '3', + fifth: 'Four', + sixth: 'Five', + seventh: 'Six', + eighth: 'Seven', + ninth: 'Seenv', +}; + describe('Select', () => { - it('uses areValuesEqual for comparing value with item in menu', () => { + it('uses areValuesEqual for comparing value with item in menu', async () => { interface ValueType { id: number; name: string; @@ -45,7 +57,7 @@ describe('Select', () => { ); const currentValueText = currentValue.name; - userEvent.click(screen.getByTestId(ButtonDataTids.root)); + await userEvent.click(screen.getByTestId(ButtonDataTids.root)); expect(screen.getByTestId(MenuDataTids.root)).toBeInTheDocument(); const menuItems = screen.getAllByTestId(MenuItemDataTids.root); @@ -64,149 +76,25 @@ describe('Select', () => { expect(onKeyDown).toHaveBeenCalledWith(expect.objectContaining({ key: 'k' })); }); - it('should execute `onFocus` with default button', () => { + it('should execute `onFocus` with default button', async () => { const onFocus = jest.fn(); render(); - userEvent.click(screen.getByTestId(ButtonDataTids.root)); + await userEvent.click(screen.getByTestId(ButtonDataTids.root)); expect(onBlur).toHaveBeenCalledTimes(1); }); - it('should search item of any type', async () => { - const first = 'One'; - const second = 'Not selectable'; - const third = 'Two'; - const fourth = '3'; - const fifth = 'Four'; - const sixth = 'Five'; - const seventh = 'Six'; - const eighth = 'Seven'; - const ninth = 'Seenv'; - render( - ); const button = screen.getByRole('button'); expect(button).toHaveAttribute('aria-expanded', 'false'); - userEvent.click(button); + await userEvent.click(button); expect(button).toHaveAttribute('aria-expanded', 'true'); }); - it('should connect dropdown with button through aria-controls', () => { + it('should connect dropdown with button through aria-controls', async () => { render( {itemsObject.second}), + itemsObject.third, + +itemsObject.fourth, + Select.SEP, + itemsObject.fifth, + {itemsObject.sixth}, + [6, itemsObject.seventh], + [7, itemsObject.eighth, 777], + itemsObject.ninth, + ]} + search + disablePortal + />, + ); + }); + it('should not show any items when `Select` is closed.', () => { + expect(screen.queryByRole('button', { name: itemsObject.first })).not.toBeInTheDocument(); + expect(screen.queryByText(itemsObject.second)).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.third })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.fourth })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.fifth })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.sixth })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.seventh })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.eighth })).not.toBeInTheDocument(); + expect(screen.queryByText(itemsObject.eighth)).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.ninth })).not.toBeInTheDocument(); + }); + it('should show all items when `Select` is opened', async () => { + const button = screen.getByRole('button', { + name: SelectLocaleHelper.get(defaultLangCode).placeholder as string, + }); + await userEvent.click(button); + + // All items should be presented when `Select` is opened. + expect(screen.getByRole('button', { name: itemsObject.first })).toBeInTheDocument(); + expect(screen.getByText(itemsObject.second)).toBeInTheDocument(); + expect(screen.getByRole('button', { name: itemsObject.third })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: itemsObject.fourth })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: itemsObject.fifth })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: itemsObject.sixth })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: itemsObject.seventh })).toBeInTheDocument(); + expect(screen.getByText(itemsObject.eighth)).toBeInTheDocument(); + expect(screen.getByRole('button', { name: itemsObject.ninth })).toBeInTheDocument(); + }); + + it('should correctly filter items on input change', async () => { + const button = screen.getByRole('button', { + name: SelectLocaleHelper.get(defaultLangCode).placeholder as string, + }); + await userEvent.click(button); + const input = screen.getByRole('textbox'); + + await userEvent.type(input, 'e'); + // After entering 'e' only `first`, `second`, `sixth`, `eighth` and `ninth` items should be presented. + expect(screen.getByRole('button', { name: itemsObject.first })).toBeInTheDocument(); + expect(screen.getByText(itemsObject.second)).toBeInTheDocument(); + expect(screen.getByRole('button', { name: itemsObject.sixth })).toBeInTheDocument(); + expect(screen.getByText(itemsObject.eighth)).toBeInTheDocument(); + expect(screen.getByRole('button', { name: itemsObject.ninth })).toBeInTheDocument(); + // All other items should not be presented + expect(screen.queryByRole('button', { name: itemsObject.third })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.fourth })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.fifth })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.seventh })).not.toBeInTheDocument(); + + await userEvent.type(input, 'v'); + // After entering 'ev' only `seventh` item should be presented. + expect(screen.getByText(itemsObject.eighth)).toBeInTheDocument(); + // All other items should not be presented. + expect(screen.queryByRole('button', { name: itemsObject.first })).not.toBeInTheDocument(); + expect(screen.queryByText(itemsObject.second)).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.third })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.fourth })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.fifth })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.sixth })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.seventh })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.ninth })).not.toBeInTheDocument(); + + await userEvent.clear(input); + // After clearing the input all items should be presented again. + expect(screen.getByRole('button', { name: itemsObject.first })).toBeInTheDocument(); + expect(screen.getByText(itemsObject.second)).toBeInTheDocument(); + expect(screen.getByRole('button', { name: itemsObject.third })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: itemsObject.fourth })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: itemsObject.fifth })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: itemsObject.sixth })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: itemsObject.seventh })).toBeInTheDocument(); + expect(screen.getByText(itemsObject.eighth)).toBeInTheDocument(); + expect(screen.getByRole('button', { name: itemsObject.ninth })).toBeInTheDocument(); + }); + it('should correctly filter items on input change (more cases)', async () => { + const button = screen.getByRole('button', { + name: SelectLocaleHelper.get(defaultLangCode).placeholder as string, + }); + await userEvent.click(button); + const input = screen.getByRole('textbox'); + + await userEvent.type(input, 's'); + // After entering 's' only `second` and `seventh` items should be presented. + expect(screen.getByText(itemsObject.second)).toBeInTheDocument(); + expect(screen.getByRole('button', { name: itemsObject.seventh })).toBeInTheDocument(); + expect(screen.getByText(itemsObject.eighth)).toBeInTheDocument(); + expect(screen.getByRole('button', { name: itemsObject.ninth })).toBeInTheDocument(); + // All other items should not be presented. + expect(screen.queryByRole('button', { name: itemsObject.first })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.third })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.fourth })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.fifth })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.sixth })).not.toBeInTheDocument(); + + await userEvent.clear(input); + + await userEvent.type(input, '3'); + // After entering '3' only `fourth` item should be presented. + expect(screen.getByRole('button', { name: itemsObject.fourth })).toBeInTheDocument(); + // All other items should not be presented. + expect(screen.queryByRole('button', { name: itemsObject.first })).not.toBeInTheDocument(); + expect(screen.queryByText(itemsObject.second)).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.third })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.fifth })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.sixth })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.seventh })).not.toBeInTheDocument(); + expect(screen.queryByText(itemsObject.eighth)).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: itemsObject.ninth })).not.toBeInTheDocument(); + }); + }); }); diff --git a/packages/react-ui/components/SidePage/SidePageFooter.tsx b/packages/react-ui/components/SidePage/SidePageFooter.tsx index 74ec198fa77..2c1b03ed63f 100644 --- a/packages/react-ui/components/SidePage/SidePageFooter.tsx +++ b/packages/react-ui/components/SidePage/SidePageFooter.tsx @@ -47,7 +47,7 @@ export const SidePageFooterDataTids = { */ @responsiveLayout @rootNode -export class SidePageFooter extends React.Component { +export class SidePageFooter extends React.Component> { public static __KONTUR_REACT_UI__ = 'SidePageFooter'; public static displayName = 'SidePageFooter'; diff --git a/packages/react-ui/components/SidePage/__creevey__/SidePage.creevey.ts b/packages/react-ui/components/SidePage/__creevey__/SidePage.creevey.ts new file mode 100644 index 00000000000..be191bb1255 --- /dev/null +++ b/packages/react-ui/components/SidePage/__creevey__/SidePage.creevey.ts @@ -0,0 +1,298 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +const simpleTests = () => { + test('open side-page', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-side-page"]' })) + .perform(); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open side-page'); + }); +}; + +kind('SidePage', () => { + story('SidePageOverAnotherSidePageStory', () => { + test('open internal side-page', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid~="open-side-page"]' })) + .perform(); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-comp-name~="SidePage.Body"] button' })) + .perform(); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open internal side-page'); + }); + + test('close internal side-page', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid~="open-side-page"]' })) + .perform(); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-comp-name~="SidePage.Body"] button' })) + .perform(); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '.react-ui:last-child [data-comp-name~="SidePage.Footer"] button' })) + .perform(); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('close internal side-page'); + }); + }); + + story('StickySidePageHeaderWhenAnotherSidePageStory', () => { + test('sticky header, open and close internal side-page', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid~="open-side-page"]' })) + .perform(); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-comp-name~="SidePage.Body"] button' })) + .perform(); + await this.browser.executeScript(function () { + const sidepageContainer = window.document.querySelector('[data-tid="SidePage__container"]'); + + if (sidepageContainer) { + sidepageContainer.scrollTop = 3000; + } + }); + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '.react-ui:last-child [data-comp-name~="SidePage.Footer"] button' })) + .perform(); + await this.expect(await this.browser.takeScreenshot()).to.matchImage( + 'sticky header, open and close internal side-page', + ); + }); + }); + + story('Simple', () => { + simpleTests(); + }); + + story('MobileSimple', () => { + simpleTests(); + }); + + story('BodyWithoutFooter', () => { + test('scroll to bottom', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-side-page"]' })) + .perform(); + await this.browser.executeScript(function () { + const sidepageContainer = window.document.querySelector('[data-tid="SidePage__container"]') as HTMLElement; + + sidepageContainer.scrollTop = 3000; + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('scroll to bottom'); + }); + }); + + story('BodyWithoutHeader', () => { + test('open side-page without header', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-side-page"]' })) + .perform(); + await delay(100); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('open side-page without header'); + }); + }); + + story('SidePageWithFocusLockWhenBackgroundBlockedFeatureFlag', ({ setStoryParameters }) => { + setStoryParameters({ skip: { 'unstable tests in firefox2022': { in: /^(?!\b(chrome2022)\b)/ } } }); + + test('open side-page', async function () { + const pressTab = async () => { + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await delay(5000); + }; + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="open-side-page"]' })) + .perform(); + await delay(1000); + await pressTab(); + const firstTimeTabPress = await this.browser.takeScreenshot(); + await pressTab(); + const secondTimeTabPress = await this.browser.takeScreenshot(); + await pressTab(); + const thirdTimeTabPress = await this.browser.takeScreenshot(); + await pressTab(); + const fourthTimeTabPress = await this.browser.takeScreenshot(); + await this.expect({ + firstTimeTabPress, + secondTimeTabPress, + thirdTimeTabPress, + fourthTimeTabPress, + }).to.matchImages(); + }); + }); + + story('TestUpdateLayoutMethodStory', () => { + test('idle', async function () { + await this.expect(await this.browser.takeScreenshot()).to.matchImage('idle'); + }); + + test('Body content has been changed', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="toggle-body-content"]' })) + .perform(); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('Body content has been changed'); + }); + + test('child component content has been changed', async function () { + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="toggle-child-component-content"]' })) + .perform(); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('child component content has been changed'); + }); + + test('update layout', async function () { + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="toggle-child-component-content"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-tid="update"]' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('update layout'); + }); + }); + + story('WithLongTitleStory', () => { + test('not fixed', async function () { + await this.expect(await this.browser.takeScreenshot()).to.matchImage('not fixed'); + }); + + test('fixed close element', async function () { + await this.browser.executeScript(function () { + const sidePageContainer = window.document.querySelector('[data-tid="SidePage__container"]') as HTMLElement; + const sidePageHeader = window.document.querySelector('[data-comp-name~="SidePage.Header"]') as HTMLElement; + const fixedHeaderHeight = 50; + + sidePageContainer.scrollTop = (sidePageHeader.offsetHeight - fixedHeaderHeight) / 2; + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('fixed close element'); + }); + + test('fixed header', async function () { + await this.browser.executeScript(function () { + const sidePageContainer = window.document.querySelector('[data-tid="SidePage__container"]') as HTMLElement; + const sidePageHeader = window.document.querySelector('[data-comp-name~="SidePage.Header"]') as HTMLElement; + const fixedHeaderHeight = 50; + + sidePageContainer.scrollTop = sidePageHeader.offsetHeight - fixedHeaderHeight; + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('fixed header'); + }); + }); + + story('SidePageWithChildrenFromOtherComponent', () => { + test('without header, footer', async function () { + await this.expect(await this.browser.takeScreenshot()).to.matchImage('without header, footer'); + }); + + test('scroll to bottom without header, footer', async function () { + await this.browser.executeScript(function () { + const sidepageContainer = window.document.querySelector('[data-tid="SidePage__container"]') as HTMLElement; + + sidepageContainer.scrollTop = 3000; + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('scroll to bottom without header, footer'); + }); + + test('with header, footer', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="SidePage__header-toggle"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-tid="SidePage__footer-toggle"]' })) + .pause(1000) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('with header, footer'); + }); + + test('scroll to bottom with header, footer', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="SidePage__header-toggle"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-tid="SidePage__footer-toggle"]' })) + .perform(); + await this.browser.executeScript(function () { + const sidepageContainer = window.document.querySelector('[data-tid="SidePage__container"]') as HTMLElement; + + sidepageContainer.scrollTop = 3000; + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('scroll to bottom with header, footer'); + }); + + test('with panel', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="SidePage__footer-toggle"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-tid="SidePage__panel-toggle"]' })) + .perform(); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('with panel'); + }); + + test('scroll to bottom with panel', async function () { + await this.browser + .actions({ bridge: true }) + .click(this.browser.findElement({ css: '[data-tid="SidePage__footer-toggle"]' })) + .pause(1000) + .click(this.browser.findElement({ css: '[data-tid="SidePage__panel-toggle"]' })) + .perform(); + await this.browser.executeScript(function () { + const sidepageContainer = window.document.querySelector('[data-tid="SidePage__container"]') as HTMLElement; + + sidepageContainer.scrollTop = 3000; + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('scroll to bottom with panel'); + }); + }); +}); diff --git a/packages/react-ui/components/SidePage/__stories__/SidePage.stories.tsx b/packages/react-ui/components/SidePage/__stories__/SidePage.stories.tsx index 64fc1f4d4d6..8f11384221b 100644 --- a/packages/react-ui/components/SidePage/__stories__/SidePage.stories.tsx +++ b/packages/react-ui/components/SidePage/__stories__/SidePage.stories.tsx @@ -1,6 +1,6 @@ import React, { useCallback, useState } from 'react'; -import { CreeveyTests, Story } from '../../../typings/stories'; +import { Story } from '../../../typings/stories'; import { SidePage } from '../SidePage'; import { Button } from '../../Button'; import { Input } from '../../Input'; @@ -9,7 +9,6 @@ import { Toggle } from '../../Toggle'; import { Modal } from '../../Modal'; import { Gapped } from '../../Gapped'; import { Shape } from '../../../typings/utility-types'; -import { delay } from '../../../lib/utils'; import { ThemeContext } from '../../../lib/theming/ThemeContext'; import { ReactUIFeatureFlagsContext } from '../../../lib/featureFlagsContext'; @@ -625,73 +624,9 @@ WithInputInHeader.parameters = { creevey: { skip: true } }; export const SidePageOverAnotherSidePageStory: Story = () => ; SidePageOverAnotherSidePageStory.storyName = 'SidePage over another SidePage'; -SidePageOverAnotherSidePageStory.parameters = { - creevey: { - tests: { - async 'open internal side-page'() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-tid~="open-side-page"]' })) - .perform(); - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-comp-name~="SidePageBody"] button' })) - .perform(); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open internal side-page'); - }, - async 'close internal side-page'() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-tid~="open-side-page"]' })) - .perform(); - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-comp-name~="SidePageBody"] button' })) - .perform(); - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '.react-ui:last-child [data-comp-name~="SidePageFooter"] button' })) - .perform(); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('close internal side-page'); - }, - }, - }, -}; - export const StickySidePageHeaderWhenAnotherSidePageStory: Story = () => ; StickySidePageHeaderWhenAnotherSidePageStory.storyName = 'Sticky SidePageHeader when another SidePage'; -StickySidePageHeaderWhenAnotherSidePageStory.parameters = { - creevey: { - tests: { - async 'sticky header, open and close internal side-page'() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-tid~="open-side-page"]' })) - .perform(); - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-comp-name~="SidePageBody"] button' })) - .perform(); - await this.browser.executeScript(function () { - const sidepageContainer = window.document.querySelector('[data-tid="SidePage__container"]'); - - if (sidepageContainer) { - sidepageContainer.scrollTop = 3000; - } - }); - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '.react-ui:last-child [data-comp-name~="SidePageFooter"] button' })) - .perform(); - await this.expect(await this.browser.takeScreenshot()).to.matchImage( - 'sticky header, open and close internal side-page', - ); - }, - }, - }, -}; - export const SidePageWithConfiguration = () => ; SidePageWithConfiguration.storyName = 'SidePage with configuration'; SidePageWithConfiguration.parameters = { creevey: { skip: true } }; @@ -719,79 +654,16 @@ export const LeftSidePageWithRightSidePageStory = () => ; -Simple.parameters = { - creevey: { - tests: simpleTests, - }, -}; - export const MobileSimple: Story = () => ; -MobileSimple.parameters = { - creevey: { - tests: simpleTests, - }, -}; - export const BodyWithoutFooter: Story = () => ; BodyWithoutFooter.storyName = 'Body without Footer'; -BodyWithoutFooter.parameters = { - creevey: { - tests: { - async 'scroll to bottom'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-side-page"]' })) - .perform(); - await this.browser.executeScript(function () { - const sidepageContainer = window.document.querySelector('[data-tid="SidePage__container"]') as HTMLElement; - - sidepageContainer.scrollTop = 3000; - }); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('scroll to bottom'); - }, - }, - }, -}; - export const BodyWithoutHeader: Story = () => ; BodyWithoutHeader.storyName = 'Body without Header'; -BodyWithoutHeader.parameters = { - creevey: { - tests: { - async 'open side-page without header'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-side-page"]' })) - .perform(); - await delay(100); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('open side-page without header'); - }, - }, - }, -}; - export const SidePageWithFocusLockWhenBackgroundBlockedFeatureFlag: Story = () => { return ( @@ -801,45 +673,6 @@ export const SidePageWithFocusLockWhenBackgroundBlockedFeatureFlag: Story = () = }; SidePageWithFocusLockWhenBackgroundBlockedFeatureFlag.storyName = 'SidePage with sidePageEnableFocusLockWhenBackgroundBlocked feature flag'; -SidePageWithFocusLockWhenBackgroundBlockedFeatureFlag.parameters = { - creevey: { - skip: { 'unstable tests in firefox2022': { in: /^(?!\b(chrome2022)\b)/ } }, - tests: { - async 'open side-page'() { - const pressTab = async () => { - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .perform(); - await delay(5000); - }; - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="open-side-page"]' })) - .perform(); - await delay(1000); - await pressTab(); - const firstTimeTabPress = await this.browser.takeScreenshot(); - await pressTab(); - const secondTimeTabPress = await this.browser.takeScreenshot(); - await pressTab(); - const thirdTimeTabPress = await this.browser.takeScreenshot(); - await pressTab(); - const fourthTimeTabPress = await this.browser.takeScreenshot(); - await this.expect({ - firstTimeTabPress, - secondTimeTabPress, - thirdTimeTabPress, - fourthTimeTabPress, - }).to.matchImages(); - }, - }, - }, -}; export const SidePageWithVariableContent = () => ; SidePageWithVariableContent.storyName = 'SidePage with variable content'; @@ -848,50 +681,6 @@ SidePageWithVariableContent.parameters = { creevey: { skip: true } }; export const TestUpdateLayoutMethodStory: Story = () => ; TestUpdateLayoutMethodStory.storyName = 'test updateLayout method'; -TestUpdateLayoutMethodStory.parameters = { - creevey: { - tests: { - async idle() { - await this.expect(await this.browser.takeScreenshot()).to.matchImage('idle'); - }, - async 'Body content has been changed'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="toggle-body-content"]' })) - .perform(); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('Body content has been changed'); - }, - async 'child component content has been changed'() { - await delay(1000); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="toggle-child-component-content"]' })) - .perform(); - await this.expect(await this.browser.takeScreenshot()).to.matchImage( - 'child component content has been changed', - ); - }, - async 'update layout'() { - await delay(1000); - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="toggle-child-component-content"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-tid="update"]' })) - .perform(); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('update layout'); - }, - }, - }, -}; - export const WithScrollableParentContentAndScrollingBeforeOpen = () => (
{textSample} @@ -910,38 +699,6 @@ WithScrollableParentContentAndScrollingBeforeOpen.parameters = { creevey: { skip export const WithLongTitleStory: Story = () => ; WithLongTitleStory.storyName = 'With long title'; -WithLongTitleStory.parameters = { - creevey: { - tests: { - async 'not fixed'() { - await this.expect(await this.browser.takeScreenshot()).to.matchImage('not fixed'); - }, - async 'fixed close element'() { - await this.browser.executeScript(function () { - const sidePageContainer = window.document.querySelector('[data-tid="SidePage__container"]') as HTMLElement; - const sidePageHeader = window.document.querySelector('[data-comp-name~="SidePageHeader"]') as HTMLElement; - const fixedHeaderHeight = 50; - - sidePageContainer.scrollTop = (sidePageHeader.offsetHeight - fixedHeaderHeight) / 2; - }); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('fixed close element'); - }, - async 'fixed header'() { - await this.browser.executeScript(function () { - const sidePageContainer = window.document.querySelector('[data-tid="SidePage__container"]') as HTMLElement; - const sidePageHeader = window.document.querySelector('[data-comp-name~="SidePageHeader"]') as HTMLElement; - const fixedHeaderHeight = 50; - - sidePageContainer.scrollTop = sidePageHeader.offsetHeight - fixedHeaderHeight; - }); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('fixed header'); - }, - }, - }, -}; - const SidePageHeader = () => Header; const SidePageBody = () => { return ( @@ -992,78 +749,3 @@ export const SidePageWithChildrenFromOtherComponent: Story = () => { }; SidePageWithChildrenFromOtherComponent.storyName = 'SidePage with Custom Children'; -SidePageWithChildrenFromOtherComponent.parameters = { - creevey: { - tests: { - async 'without header, footer'() { - await this.expect(await this.browser.takeScreenshot()).to.matchImage('without header, footer'); - }, - async 'scroll to bottom without header, footer'() { - await this.browser.executeScript(function () { - const sidepageContainer = window.document.querySelector('[data-tid="SidePage__container"]') as HTMLElement; - - sidepageContainer.scrollTop = 3000; - }); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('scroll to bottom without header, footer'); - }, - async 'with header, footer'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="SidePage__header-toggle"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-tid="SidePage__footer-toggle"]' })) - .pause(1000) - .perform(); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('with header, footer'); - }, - async 'scroll to bottom with header, footer'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="SidePage__header-toggle"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-tid="SidePage__footer-toggle"]' })) - .perform(); - await this.browser.executeScript(function () { - const sidepageContainer = window.document.querySelector('[data-tid="SidePage__container"]') as HTMLElement; - - sidepageContainer.scrollTop = 3000; - }); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('scroll to bottom with header, footer'); - }, - async 'with panel'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid="SidePage__footer-toggle"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-tid="SidePage__panel-toggle"]' })) - .perform(); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('with panel'); - }, - async 'scroll to bottom with panel'() { - await this.browser - .actions({ bridge: true }) - .click(this.browser.findElement({ css: '[data-tid="SidePage__footer-toggle"]' })) - .pause(1000) - .click(this.browser.findElement({ css: '[data-tid="SidePage__panel-toggle"]' })) - .perform(); - await this.browser.executeScript(function () { - const sidepageContainer = window.document.querySelector('[data-tid="SidePage__container"]') as HTMLElement; - - sidepageContainer.scrollTop = 3000; - }); - await delay(1000); - await this.expect(await this.browser.takeScreenshot()).to.matchImage('scroll to bottom with panel'); - }, - }, - }, -}; diff --git a/packages/react-ui/components/SidePage/__tests__/SidePage.test.tsx b/packages/react-ui/components/SidePage/__tests__/SidePage.test.tsx index c2d0e375340..63b564706d3 100644 --- a/packages/react-ui/components/SidePage/__tests__/SidePage.test.tsx +++ b/packages/react-ui/components/SidePage/__tests__/SidePage.test.tsx @@ -9,7 +9,7 @@ import { componentsLocales as SidePageLocalesEn } from '../locale/locales/en'; import { componentsLocales as SidePageLocalesRu } from '../locale/locales/ru'; describe('SidePage', () => { - it('onClose event performs an action on click', () => { + it('onClose event performs an action on click', async () => { const onClose = jest.fn(); render( @@ -21,7 +21,7 @@ describe('SidePage', () => { expect(onClose).not.toHaveBeenCalled(); - userEvent.click(closeButton); + await userEvent.click(closeButton); expect(onClose).toHaveBeenCalledTimes(1); }); diff --git a/packages/react-ui/components/SingleToast/__tests__/SingleToast.test.tsx b/packages/react-ui/components/SingleToast/__tests__/SingleToast.test.tsx index 03aa32aa336..2a45825dae6 100644 --- a/packages/react-ui/components/SingleToast/__tests__/SingleToast.test.tsx +++ b/packages/react-ui/components/SingleToast/__tests__/SingleToast.test.tsx @@ -10,7 +10,7 @@ import { ToastLocaleHelper } from '../../Toast/locale'; describe('ToastView', () => { describe('a11y', () => { - it('has correct aria-label on close button', () => { + it('has correct aria-label on close button', async () => { function showComplexNotification() { SingleToast.push( 'Successfully saved', @@ -28,7 +28,7 @@ describe('ToastView', () => { , ); - userEvent.click(screen.getByRole('button')); + await userEvent.click(screen.getByRole('button')); expect(screen.getByTestId(ToastDataTids.close)).toHaveAttribute( 'aria-label', @@ -57,7 +57,7 @@ describe('ToastView', () => { , ); - userEvent.click(screen.getByRole('button', { name: buttonName })); + await userEvent.click(screen.getByRole('button', { name: buttonName })); expect(screen.getByTestId(ToastDataTids.action)).toHaveAttribute('aria-label', ariaLabel); }); diff --git a/packages/react-ui/components/Spinner/__stories__/Spinner.stories.tsx b/packages/react-ui/components/Spinner/__stories__/Spinner.stories.tsx index 979948feb80..108eee61591 100644 --- a/packages/react-ui/components/Spinner/__stories__/Spinner.stories.tsx +++ b/packages/react-ui/components/Spinner/__stories__/Spinner.stories.tsx @@ -30,7 +30,7 @@ export default { }, }, decorators: [ - (Story) => ( + (Story: () => JSX.Element) => (
diff --git a/packages/react-ui/components/Sticky/__creevey__/Sticky.creevey.ts b/packages/react-ui/components/Sticky/__creevey__/Sticky.creevey.ts new file mode 100644 index 00000000000..7961432fa4b --- /dev/null +++ b/packages/react-ui/components/Sticky/__creevey__/Sticky.creevey.ts @@ -0,0 +1,104 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('Sticky', () => { + story('WideContainer', () => { + test('fixed', async function () { + await this.browser.executeScript(function () { + const stickyContent = window.document.querySelector('[data-tid="stickyContent"]') as HTMLElement; + const nonStickyText = window.document.querySelector('[data-tid="nonStickyText"]') as HTMLElement; + const scrollXOffset = nonStickyText.getBoundingClientRect().width / 2; + const scrollYOffset = stickyContent.getBoundingClientRect().height / 2; + + window.scrollTo(scrollXOffset, scrollYOffset); + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('fixed'); + }); + }); + + story('Top', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'flacky stopped position': { in: ['firefox', 'firefox8px', 'firefoxDark'], tests: 'stoped' }, + }, + }); + + test('top', async function () { + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('top'); + }); + + test('fixed', async function () { + await this.browser.executeScript(function () { + const stickyStop = window.document.querySelector('[data-tid="stickyStop"]') as HTMLElement; + const scrollOffset = stickyStop.getBoundingClientRect().top - window.innerHeight / 2; + + window.scrollTo(0, scrollOffset); + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('fixed'); + }); + + test('stoped', async function () { + await this.browser.executeScript(function () { + const stickyStop = window.document.querySelector('[data-tid="stickyStop"]') as HTMLElement; + stickyStop.scrollIntoView(); + }); + await this.browser.executeScript(function () { + const stickyContent = window.document.querySelector('[data-tid="stickyContent"]') as HTMLElement; + const scrollOffset = pageYOffset - stickyContent.getBoundingClientRect().height / 2; + + window.scrollTo(0, scrollOffset); + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('stoped'); + }); + }); + + story('Bottom', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'flacky stopped position': { + in: ['firefox', 'firefox8px', 'firefoxDark'], + tests: 'stoped', + }, + }, + }); + + test('bottom', async function () { + await this.browser.executeScript(function () { + window.scrollTo(0, 9999); + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('bottom'); + }); + + test('fixed', async function () { + await this.browser.executeScript(function () { + const sticky = window.document.querySelector('[data-comp-name~="Sticky"]') as HTMLElement; + const scrollOffset = sticky.getBoundingClientRect().top - window.innerHeight; + + window.scrollTo(0, scrollOffset); + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('fixed'); + }); + + test('stoped', async function () { + await this.browser.executeScript(function () { + const stickyStop = window.document.querySelector('[data-tid="stickyStop"]') as HTMLElement; + stickyStop.scrollIntoView(false); + }); + await this.browser.executeScript(function () { + const stickyContent = window.document.querySelector('[data-tid="stickyContent"]') as HTMLElement; + const scrollOffset = pageYOffset + stickyContent.getBoundingClientRect().height / 2; + + window.scrollTo(0, scrollOffset); + }); + await delay(1000); + await this.expect(await this.browser.takeScreenshot()).to.matchImage('fixed'); + }); + }); +}); diff --git a/packages/react-ui/components/Sticky/__stories__/Sticky.stories.tsx b/packages/react-ui/components/Sticky/__stories__/Sticky.stories.tsx index cc33e186002..9538fcb3068 100644 --- a/packages/react-ui/components/Sticky/__stories__/Sticky.stories.tsx +++ b/packages/react-ui/components/Sticky/__stories__/Sticky.stories.tsx @@ -2,7 +2,6 @@ import React from 'react'; import { Story } from '../../../typings/stories'; import { Sticky } from '../Sticky'; -import { delay } from '../../../lib/utils'; const stickyContent = (fixed: boolean) => (
( +const withThinContainer = (Story: () => JSX.Element) => (
@@ -117,119 +116,13 @@ export default { title: 'Sticky' }; export const WideContainer: Story = () => ; -WideContainer.parameters = { - creevey: { - tests: { - async fixed() { - await this.browser.executeScript(function () { - const stickyContent = window.document.querySelector('[data-tid="stickyContent"]') as HTMLElement; - const nonStickyText = window.document.querySelector('[data-tid="nonStickyText"]') as HTMLElement; - const scrollXOffset = nonStickyText.getBoundingClientRect().width / 2; - const scrollYOffset = stickyContent.getBoundingClientRect().height / 2; - - window.scrollTo(scrollXOffset, scrollYOffset); - }); - await delay(1000); - - await this.expect(await this.browser.takeScreenshot()).to.matchImage('fixed'); - }, - }, - }, -}; - export const Top: Story = () => ; -Top.decorators = [withThinContainer]; -Top.parameters = { - creevey: { - skip: { - 'flacky stopped position': { in: ['firefox', 'firefox8px', 'firefoxDark'], tests: 'stoped' }, - }, - tests: { - async top() { - await delay(1000); - - await this.expect(await this.browser.takeScreenshot()).to.matchImage('top'); - }, - async fixed() { - await this.browser.executeScript(function () { - const stickyStop = window.document.querySelector('[data-tid="stickyStop"]') as HTMLElement; - const scrollOffset = stickyStop.getBoundingClientRect().top - window.innerHeight / 2; - - window.scrollTo(0, scrollOffset); - }); - await delay(1000); - - await this.expect(await this.browser.takeScreenshot()).to.matchImage('fixed'); - }, - async stoped() { - await this.browser.executeScript(function () { - const stickyStop = window.document.querySelector('[data-tid="stickyStop"]') as HTMLElement; - stickyStop.scrollIntoView(); - }); - await this.browser.executeScript(function () { - const stickyContent = window.document.querySelector('[data-tid="stickyContent"]') as HTMLElement; - const scrollOffset = pageYOffset - stickyContent.getBoundingClientRect().height / 2; - - window.scrollTo(0, scrollOffset); - }); - await delay(1000); - - await this.expect(await this.browser.takeScreenshot()).to.matchImage('stoped'); - }, - }, - }, -}; +Top.decorators = [withThinContainer as () => JSX.Element]; export const Bottom: Story = () => ; -Bottom.decorators = [withThinContainer]; -Bottom.parameters = { - creevey: { - skip: { - 'flacky stopped position': { - in: ['firefox', 'firefox8px', 'firefoxDark'], - tests: 'stoped', - }, - }, - tests: { - async bottom() { - await this.browser.executeScript(function () { - window.scrollTo(0, 9999); - }); - await delay(1000); - - await this.expect(await this.browser.takeScreenshot()).to.matchImage('bottom'); - }, - async fixed() { - await this.browser.executeScript(function () { - const sticky = window.document.querySelector('[data-comp-name~="Sticky"]') as HTMLElement; - const scrollOffset = sticky.getBoundingClientRect().top - window.innerHeight; - - window.scrollTo(0, scrollOffset); - }); - await delay(1000); - - await this.expect(await this.browser.takeScreenshot()).to.matchImage('fixed'); - }, - async stoped() { - await this.browser.executeScript(function () { - const stickyStop = window.document.querySelector('[data-tid="stickyStop"]') as HTMLElement; - stickyStop.scrollIntoView(false); - }); - await this.browser.executeScript(function () { - const stickyContent = window.document.querySelector('[data-tid="stickyContent"]') as HTMLElement; - const scrollOffset = pageYOffset + stickyContent.getBoundingClientRect().height / 2; - - window.scrollTo(0, scrollOffset); - }); - await delay(1000); - - await this.expect(await this.browser.takeScreenshot()).to.matchImage('fixed'); - }, - }, - }, -}; +Bottom.decorators = [withThinContainer as () => JSX.Element]; export const FlexContainer = () => ; FlexContainer.storyName = 'Flex container'; diff --git a/packages/react-ui/components/Switcher/__creevey__/Switcher.creevey.ts b/packages/react-ui/components/Switcher/__creevey__/Switcher.creevey.ts new file mode 100644 index 00000000000..be710a2eec2 --- /dev/null +++ b/packages/react-ui/components/Switcher/__creevey__/Switcher.creevey.ts @@ -0,0 +1,30 @@ +import { story, kind, test } from 'creevey'; + +kind('Switcher', () => { + story('Horizontal', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['chromeFlat8px'], tests: 'clicked' }, + }, + }); + + test('idle', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('idle'); + }); + + test('clicked', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Button"]' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); + }); + }); + story('WithCustomRenderItems', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { 'chrome only': { in: /^(?!\bchrome\b)/ } }, + }); + }); +}); diff --git a/packages/react-ui/components/Switcher/__stories__/Switcher.stories.tsx b/packages/react-ui/components/Switcher/__stories__/Switcher.stories.tsx index aa8ffad51ad..83e69781bb6 100644 --- a/packages/react-ui/components/Switcher/__stories__/Switcher.stories.tsx +++ b/packages/react-ui/components/Switcher/__stories__/Switcher.stories.tsx @@ -38,28 +38,6 @@ export const Horizontal: Story = () => { }; Horizontal.storyName = 'horizontal'; -Horizontal.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['chromeFlat8px'], tests: 'clicked' }, - }, - tests: { - async idle() { - await this.expect(await this.takeScreenshot()).to.matchImage('idle'); - }, - async clicked() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Button"]' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); - }, - }, - }, -}; - export const Errored = () => { return ; }; @@ -152,8 +130,3 @@ export const WithCustomRenderItems: Story = () => { }; WithCustomRenderItems.storyName = 'with custom render item'; -WithCustomRenderItems.parameters = { - creevey: { - skip: { 'chrome only': { in: /^(?!\bchrome\b)/ } }, - }, -}; diff --git a/packages/react-ui/components/Switcher/__tests__/Switcher-test.tsx b/packages/react-ui/components/Switcher/__tests__/Switcher-test.tsx index 780d77cbd4d..63fa3e2b6b4 100644 --- a/packages/react-ui/components/Switcher/__tests__/Switcher-test.tsx +++ b/packages/react-ui/components/Switcher/__tests__/Switcher-test.tsx @@ -39,36 +39,36 @@ describe('Switcher', () => { expect(renderSwitcher).not.toThrow(); }); - it('should select item', () => { + it('should select item', async () => { render(); const buttons = screen.getAllByRole(switchDefaultRole); expect(buttons[1]).not.toBeChecked(); - userEvent.click(buttons[1]); + await userEvent.click(buttons[1]); expect(buttons[1]).toBeChecked(); }); - it('should select item if enter key is pressed and not buttonProps.disabled', () => { + it('should select item if enter key is pressed and not buttonProps.disabled', async () => { render(); const buttons = screen.getAllByRole(switchDefaultRole); expect(buttons[0]).not.toBeChecked(); buttons[0].focus(); - userEvent.keyboard('{enter}'); + await userEvent.keyboard('{enter}'); expect(buttons[0]).toBeChecked(); }); - it('should not select item if enter key is pressed and buttonProps.disabled', () => { + it('should not select item if enter key is pressed and buttonProps.disabled', async () => { render(); const buttons = screen.getAllByRole(switchDefaultRole); expect(buttons[2]).not.toBeChecked(); buttons[2].focus(); - userEvent.keyboard('{enter}'); + await userEvent.keyboard('{enter}'); expect(buttons[2]).not.toBeChecked(); }); diff --git a/packages/react-ui/components/Tabs/__creevey__/Tabs.creevey.ts b/packages/react-ui/components/Tabs/__creevey__/Tabs.creevey.ts new file mode 100644 index 00000000000..1c8533a9d49 --- /dev/null +++ b/packages/react-ui/components/Tabs/__creevey__/Tabs.creevey.ts @@ -0,0 +1,268 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +const tabsSimpleTests = () => { + test('move focus forward', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(1)' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ARROW_RIGHT) + .pause(500) + .sendKeys(this.keys.ARROW_DOWN) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('move focus forward'); + }); + test('move focus backward', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(3)' })) + .perform(); + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ARROW_LEFT) + .perform(); + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ARROW_UP) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('move focus backward'); + }); + test('reset focus after click', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(1)' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ARROW_RIGHT) + .pause(500) + .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(3)' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('reset focus after click'); + }); +}; +const tabsTests = () => { + test('plain', async function () { + await this.expect(await this.takeScreenshot()).to.matchImage('plain'); + }); + + test('hovered', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ + origin: this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(2)' }), + }) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); + }); + + test('clicked', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(2)' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); + }); + + test('mouseLeave', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(2)' })) + .move({ + origin: this.browser.findElement({ css: 'body' }), + }) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('mouseLeave'); + }); + + test('focused', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(2)' })) + .move({ + origin: this.browser.findElement({ css: 'body' }), + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(2)' })) + .perform(); + await this.expect(await this.takeScreenshot()).to.matchImage('focused'); + }); + + test('tabPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(2)' })) + .perform(); + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); + }); + + test('enterPress', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(2)' })) + .perform(); + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.TAB) + .perform(); + await delay(1000); + await this.browser + .actions({ + bridge: true, + }) + .sendKeys(this.keys.ENTER) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('enterPress'); + }); +}; + +kind('Tabs', () => { + story('WithDisabledTab', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'hovered' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'focused', 'tabPress'], + }, + }, + }); + + tabsTests(); + }); + story('Simple', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'hovered' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'focused', 'tabPress'], + }, + }, + }); + + tabsTests(); + tabsSimpleTests(); + }); + story('SimpleMedium', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'hovered' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'focused', 'tabPress'], + }, + }, + }); + + tabsTests(); + tabsSimpleTests(); + }); + story('SimpleSmall', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'hovered' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'focused', 'tabPress'], + }, + }, + }); + + tabsTests(); + tabsSimpleTests(); + }); + story('Vertical', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'hovered' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'focused', 'tabPress', 'enterPress'], + }, + }, + }); + tabsTests(); + }); + story('VerticalMedium', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'hovered' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'focused', 'tabPress', 'enterPress'], + }, + }, + }); + tabsTests(); + }); + story('VerticalSmall', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'hovered' }, + + // TODO @Khlutkova fix after update browsers + 'story-skip-1': { + in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], + tests: ['hovered', 'focused', 'tabPress', 'enterPress'], + }, + }, + }); + tabsTests(); + }); +}); diff --git a/packages/react-ui/components/Tabs/__stories__/Tabs.stories.tsx b/packages/react-ui/components/Tabs/__stories__/Tabs.stories.tsx index d238b2e9369..cce6dd65e08 100644 --- a/packages/react-ui/components/Tabs/__stories__/Tabs.stories.tsx +++ b/packages/react-ui/components/Tabs/__stories__/Tabs.stories.tsx @@ -1,18 +1,14 @@ -/* eslint-disable jsx-a11y/anchor-has-content */ -/* eslint-disable jsx-a11y/accessible-emoji */ // TODO: Rewrite stories and enable rule (in process of functional refactoring). /* eslint-disable react/no-unstable-nested-components */ import React, { useState } from 'react'; import { linkTo } from '@storybook/addon-links'; -import { Parameters } from '@storybook/react'; -import { Story, CreeveyTests } from '../../../typings/stories'; +import { Story } from '../../../typings/stories'; import { ComponentTable } from '../../../internal/ComponentTable'; import { Tabs } from '../Tabs'; import { TabProps } from '../Tab'; import { Modal } from '../../Modal'; import { Button } from '../../Button'; -import { delay } from '../../../lib/utils'; import { TabsProps } from '..'; import { SizeProp } from '../../../lib/types/props'; const { Tab } = Tabs; @@ -166,7 +162,7 @@ interface UnexpectedUpdatedTabProps { id: string; } -class UnexpectedUpdatedTab extends React.Component { +class UnexpectedUpdatedTab extends React.Component> { public state = { updated: false, }; @@ -368,187 +364,14 @@ class TabsTable extends React.Component { export default { title: 'Tabs' }; -const tabsTests: CreeveyTests = { - async plain() { - await this.expect(await this.takeScreenshot()).to.matchImage('plain'); - }, - async hovered() { - await this.browser - .actions({ - bridge: true, - }) - .move({ - origin: this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(2)' }), - }) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('hovered'); - }, - async clicked() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(2)' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('clicked'); - }, - async mouseLeave() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(2)' })) - .move({ - origin: this.browser.findElement({ css: 'body' }), - }) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('mouseLeave'); - }, - async focused() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(2)' })) - .move({ - origin: this.browser.findElement({ css: 'body' }), - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(2)' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('focused'); - }, - async tabPress() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(2)' })) - .perform(); - await delay(1000); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .perform(); - await delay(1000); - await this.expect(await this.takeScreenshot()).to.matchImage('tabPress'); - }, - async enterPress() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(2)' })) - .perform(); - await delay(1000); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.TAB) - .perform(); - await delay(1000); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.ENTER) - .perform(); - await delay(1000); - await this.expect(await this.takeScreenshot()).to.matchImage('enterPress'); - }, -}; - -const tabsSimpleTests: CreeveyTests = { - async 'move focus forward'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(1)' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.ARROW_RIGHT) - .pause(500) - .sendKeys(this.keys.ARROW_DOWN) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('move focus forward'); - }, - async 'move focus backward'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(3)' })) - .perform(); - await delay(1000); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.ARROW_LEFT) - .perform(); - await delay(1000); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.ARROW_UP) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('move focus backward'); - }, - async 'reset focus after click'() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(1)' })) - .perform(); - await this.browser - .actions({ - bridge: true, - }) - .sendKeys(this.keys.ARROW_RIGHT) - .pause(500) - .click(this.browser.findElement({ css: '[data-comp-name~="Tab"]:nth-child(3)' })) - .perform(); - await this.expect(await this.takeScreenshot()).to.matchImage('reset focus after click'); - }, -}; - -const simpleParameters: Parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'hovered' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { - in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], - tests: ['hovered', 'focused', 'tabPress'], - }, - }, - tests: { - ...tabsTests, - ...tabsSimpleTests, - }, - }, -}; - export const Simple: Story = () => ; Simple.storyName = 'simple'; -Simple.parameters = simpleParameters; export const SimpleMedium: Story = () => ; SimpleMedium.storyName = 'simple (size=medium)'; -SimpleMedium.parameters = simpleParameters; export const SimpleSmall: Story = () => ; SimpleSmall.storyName = 'simple (size=small)'; -SimpleSmall.parameters = simpleParameters; export const First = () => ; First.storyName = 'first'; @@ -576,32 +399,14 @@ export const HrefsSecond = () => ( HrefsSecond.storyName = 'hrefs second'; HrefsSecond.parameters = { creevey: { skip: true } }; -const verticalParams: Parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'hovered' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { - in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], - tests: ['hovered', 'focused', 'tabPress', 'enterPress'], - }, - }, - tests: tabsTests, - }, -}; - export const Vertical: Story = () => ; Vertical.storyName = 'vertical'; -Vertical.parameters = verticalParams; export const VerticalMedium: Story = () => ; VerticalMedium.storyName = 'vertical (size=medium)'; -VerticalMedium.parameters = verticalParams; export const VerticalSmall: Story = () => ; VerticalSmall.storyName = 'vertical (size=small)'; -VerticalSmall.parameters = verticalParams; export const WithLink = () => ; WithLink.parameters = { creevey: { skip: true } }; @@ -644,20 +449,6 @@ WithUnexpectedTabSizeChange.parameters = { creevey: { skip: true } }; export const WithDisabledTab: Story = () => ; WithDisabledTab.storyName = 'with disabled tab'; -WithDisabledTab.parameters = { - creevey: { - skip: { - 'story-skip-0': { in: ['ie11', 'ie118px', 'ie11Dark'], tests: 'hovered' }, - - // TODO @Khlutkova fix after update browsers - 'story-skip-1': { - in: ['chrome8px', 'chromeFlat8px', 'chrome', 'chromeDark'], - tests: ['hovered', 'focused', 'tabPress'], - }, - }, - tests: tabsTests, - }, -}; export const TabsInModalStory = () => ; TabsInModalStory.storyName = 'tabs in modal'; diff --git a/packages/react-ui/components/Tabs/__tests__/Tab.test.tsx b/packages/react-ui/components/Tabs/__tests__/Tab.test.tsx index aebe3769a77..ebb784de94f 100644 --- a/packages/react-ui/components/Tabs/__tests__/Tab.test.tsx +++ b/packages/react-ui/components/Tabs/__tests__/Tab.test.tsx @@ -13,7 +13,7 @@ describe('Tab', () => { expect(() => render()).not.toThrow(); }); - it('should handle OnClick event', () => { + it('should handle OnClick event', async () => { const onClick = jest.fn(); render( @@ -26,12 +26,12 @@ describe('Tab', () => { ); const tabs = screen.getAllByTestId(TabDataTids.root); - userEvent.click(tabs[1]); + await userEvent.click(tabs[1]); expect(onClick).toHaveBeenCalledTimes(1); }); - it('should handle onKeyDown event', () => { + it('should handle onKeyDown event', async () => { const onKeyDown = jest.fn(); render( @@ -42,12 +42,12 @@ describe('Tab', () => { Alps , ); - userEvent.type(screen.getAllByTestId(TabDataTids.root)[1], '{enter}'); + await userEvent.type(screen.getAllByTestId(TabDataTids.root)[1], '{enter}'); expect(onKeyDown).toHaveBeenCalledTimes(1); }); - it('should not call onKeyDown event on disabled tab', () => { + it('should not call onKeyDown event on disabled tab', async () => { const onKeyDown = jest.fn(); render( @@ -58,12 +58,12 @@ describe('Tab', () => { Alps , ); - userEvent.type(screen.getAllByTestId(TabDataTids.root)[1], '{enter}'); + await userEvent.type(screen.getAllByTestId(TabDataTids.root)[1], '{enter}'); expect(onKeyDown).not.toHaveBeenCalled(); }); - it('should focus by tab', () => { + it('should focus by tab', async () => { render( Fuji @@ -71,11 +71,11 @@ describe('Tab', () => { ); expect(screen.getByTestId(TabDataTids.root)).not.toHaveFocus(); - userEvent.tab(); + await userEvent.tab(); expect(screen.getByTestId(TabDataTids.root)).toHaveFocus(); }); - it('should pass focus by arrowright press', () => { + it('should pass focus by arrowright press', async () => { render( Fuji @@ -84,15 +84,15 @@ describe('Tab', () => { ); const tabs = screen.getAllByTestId(TabDataTids.root); expect(tabs[0]).not.toHaveFocus(); - userEvent.tab(); + await userEvent.tab(); expect(tabs[0]).toHaveFocus(); - userEvent.type(tabs[0], '{arrowright}'); + await userEvent.type(tabs[0], '{arrowright}'); expect(tabs[0]).not.toHaveFocus(); expect(tabs[1]).toHaveFocus(); }); - it('should focus by arrowleft', () => { + it('should focus by arrowleft', async () => { render( Fuji @@ -101,17 +101,17 @@ describe('Tab', () => { ); const tabs = screen.getAllByTestId(TabDataTids.root); expect(tabs[0]).not.toHaveFocus(); - userEvent.tab(); + await userEvent.tab(); expect(tabs[0]).toHaveFocus(); - userEvent.type(tabs[0], '{arrowright}'); + await userEvent.type(tabs[0], '{arrowright}'); expect(tabs[0]).not.toHaveFocus(); - userEvent.type(tabs[0], '{arrowleft}'); + await userEvent.type(tabs[0], '{arrowleft}'); expect(tabs[0]).toHaveFocus(); }); - it('should not focus on disabled tab by pressing tab', () => { + it('should not focus on disabled tab by pressing tab', async () => { render( Fuji @@ -124,10 +124,10 @@ describe('Tab', () => { const tabs = screen.getAllByTestId(TabDataTids.root); - userEvent.tab(); + await userEvent.tab(); expect(tabs[0]).toHaveFocus(); - userEvent.tab(); + await userEvent.tab(); expect(tabs[0]).not.toHaveFocus(); expect(tabs[1]).not.toHaveFocus(); expect(tabs[2]).toHaveFocus(); @@ -142,7 +142,7 @@ describe('Tab', () => { , ); - expect(screen.getByRole('link')).toHaveAttribute('aria-label', ariaLabel); + expect(screen.getByTestId(TabDataTids.root)).toHaveAttribute('aria-label', ariaLabel); }); }); }); diff --git a/packages/react-ui/components/Tabs/__tests__/Tabs-test.tsx b/packages/react-ui/components/Tabs/__tests__/Tabs-test.tsx index 674272920c8..eb2cccd410e 100644 --- a/packages/react-ui/components/Tabs/__tests__/Tabs-test.tsx +++ b/packages/react-ui/components/Tabs/__tests__/Tabs-test.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/display-name */ import React from 'react'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; @@ -40,7 +39,7 @@ describe('Tabs', () => { expect(screen.getByTestId(TabsDataTids.root)).toBeInTheDocument(); }); - it('should call onValueChange when switch tabs', () => { + it('should call onValueChange when switch tabs', async () => { const onValueChange = jest.fn(); render( @@ -50,7 +49,7 @@ describe('Tabs', () => { , ); const tabs = screen.getAllByTestId(TabDataTids.root); - userEvent.click(tabs[1]); + await userEvent.click(tabs[1]); expect(onValueChange).toHaveBeenCalledTimes(1); }); @@ -68,7 +67,7 @@ describe('Tabs', () => {

Description Tabs

, ); - const tab = screen.getByRole('link'); + const tab = screen.getByTestId(TabDataTids.root); expect(tab).toHaveAttribute('aria-describedby', 'elementTabId'); expect(tab).toHaveAccessibleDescription('Description Tab item'); diff --git a/packages/react-ui/components/Textarea/Textarea.tsx b/packages/react-ui/components/Textarea/Textarea.tsx index eb8fe835ad3..d7ec25b096c 100644 --- a/packages/react-ui/components/Textarea/Textarea.tsx +++ b/packages/react-ui/components/Textarea/Textarea.tsx @@ -1,5 +1,3 @@ -// TODO: Enable this rule in functional components. -/* eslint-disable @typescript-eslint/no-unused-vars */ import React, { AriaAttributes, ReactNode } from 'react'; import PropTypes from 'prop-types'; import throttle from 'lodash.throttle'; @@ -311,7 +309,7 @@ export class Textarea extends React.Component { {(theme) => { this.theme = theme; return ( - + {this.renderMain} ); diff --git a/packages/react-ui/components/Textarea/TextareaCounter.tsx b/packages/react-ui/components/Textarea/TextareaCounter.tsx index bf681d0f8bb..fb6dbde5f4f 100644 --- a/packages/react-ui/components/Textarea/TextareaCounter.tsx +++ b/packages/react-ui/components/Textarea/TextareaCounter.tsx @@ -43,7 +43,12 @@ export const TextareaCounter = forwardRefAndName ({ reflow }), [reflow]); - const renderTooltipContent = useCallback(() => help, [help]); + const renderTooltipContent = useCallback(() => { + if (typeof help === 'function') { + return help(); + } + return help; + }, [help]); const textareaValue = value ? value.toString().length : 0; const counterValue = length - textareaValue; @@ -97,5 +102,5 @@ TextareaCounter.propTypes = { value: propTypes.oneOfType([propTypes.string, propTypes.number]), help: propTypes.oneOfType([propTypes.node, propTypes.func]), onCloseHelp: propTypes.func.isRequired, - textarea: safePropTypesInstanceOf(globalObject.HTMLElement).isRequired, + textarea: safePropTypesInstanceOf(globalObject.HTMLTextAreaElement).isRequired, }; diff --git a/packages/react-ui/components/Textarea/__creevey__/Textarea.creevey.ts b/packages/react-ui/components/Textarea/__creevey__/Textarea.creevey.ts new file mode 100644 index 00000000000..0ae99b26d37 --- /dev/null +++ b/packages/react-ui/components/Textarea/__creevey__/Textarea.creevey.ts @@ -0,0 +1,176 @@ +import { story, kind, test } from 'creevey'; + +import { delay } from '../../../lib/utils'; + +kind('Textarea', () => { + story('DifferentStates', () => { + test('Plain', async function () { + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); + }); + + test('Focus', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#TextareaPlain textarea' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('Focus'); + }); + + test('FocusedByTab', async function () { + await this.browser + .actions({ + bridge: true, + }) + .move({ x: 0, y: 0 }) + .click() + .sendKeys(this.keys.TAB) + .sendKeys(this.keys.TAB) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('Focused by tab'); + }); + + test('Typed', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#TextareaPlain textarea' })) + .sendKeys('Test...') + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('Typed'); + }); + }); + + story('AutoresizableTextareaStory', () => { + test('autoresize', async function () { + const textArea = () => this.browser.findElement({ css: '[data-tid~="TextArea"]' }); + const before = await textArea().takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="AddButton"]' })) + .pause(500) + .perform(); + const addText = await textArea().takeScreenshot(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid~="CollapseButton"]' })) + .pause(500) + .perform(); + const collapse = await textArea().takeScreenshot(); + await this.expect({ before, addText, collapse }).to.matchImages(); + }); + }); + + story('SelectAllByProp', () => { + test('Plain', async function () { + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); + }); + + test('Focused', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: 'label' })) + .pause(500) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('Focused'); + }); + }); + + story('SelectAllByButton', () => { + test('Plain', async function () { + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); + }); + + test('Selected', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '[data-tid="select-all"]' })) + .pause(500) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('Selected'); + }); + }); + + story('TextareaWithCounters', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'flacky scrollbars height': { + in: ['firefox', 'firefox8px', 'firefoxFlat8px', 'firefoxDark'], + }, + }, + }); + + test('Plain', async function () { + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); + }); + + test('Focus', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#CounterPlain textarea' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('Focus'); + }); + + test('FocusAutoresize', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#CounterAutoresizeTextarea textarea' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('FocusAutoresize'); + }); + + test('FocusWithHelpClosed', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#CounterWithHelp textarea' })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('CounterWithHelp'); + }); + + test('FocusWithHelpOpened', async function () { + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: '#CounterWithHelp textarea' })) + .perform(); + await this.browser + .actions({ + bridge: true, + }) + .click(this.browser.findElement({ css: `svg` })) + .perform(); + await delay(1000); + await this.expect(await this.takeScreenshot()).to.matchImage('CounterWithHelpOpened'); + }); + }); +}); diff --git a/packages/react-ui/components/Textarea/__stories__/Textarea.stories.tsx b/packages/react-ui/components/Textarea/__stories__/Textarea.stories.tsx index 171b622472d..8cd44f2741a 100644 --- a/packages/react-ui/components/Textarea/__stories__/Textarea.stories.tsx +++ b/packages/react-ui/components/Textarea/__stories__/Textarea.stories.tsx @@ -4,7 +4,6 @@ import { Story } from '../../../typings/stories'; import { Textarea } from '../Textarea'; import { Button } from '../../Button'; import { Gapped } from '../../Gapped'; -import { delay } from '../../../lib/utils'; const TEXT_SAMPLE = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Modi enim voluptatum esse, id libero voluptas similique beatae, molestiae, impedit corrupti corporis asperiores odit ullam provident officia alias aperiam eum quas.'; @@ -136,55 +135,6 @@ export const DifferentStates: Story = () => { }; DifferentStates.storyName = 'Different states'; -DifferentStates.parameters = { - creevey: { - tests: { - async Plain() { - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('Plain'); - }, - async Focus() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#TextareaPlain textarea' })) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('Focus'); - }, - async FocusedByTab() { - await this.browser - .actions({ - bridge: true, - }) - .move({ x: 0, y: 0 }) - .click() - .sendKeys(this.keys.TAB) - .sendKeys(this.keys.TAB) - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('Focused by tab'); - }, - async Typed() { - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '#TextareaPlain textarea' })) - .sendKeys('Test...') - .perform(); - await delay(1000); - - await this.expect(await this.takeScreenshot()).to.matchImage('Typed'); - }, - }, - }, -}; - export const TextareaWithPlaceholder = () => (
@@ -210,39 +160,6 @@ TextareaInInlineFlexAndText.parameters = { creevey: { skip: true } }; export const AutoresizableTextareaStory: Story = () => ; AutoresizableTextareaStory.storyName = 'Autoresizable textarea'; -AutoresizableTextareaStory.parameters = { - creevey: { - tests: { - async autoresize() { - const textArea = () => this.browser.findElement({ css: '[data-tid~="TextArea"]' }); - - const before = await textArea().takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="AddButton"]' })) - .pause(500) - .perform(); - - const addText = await textArea().takeScreenshot(); - - await this.browser - .actions({ - bridge: true, - }) - .click(this.browser.findElement({ css: '[data-tid~="CollapseButton"]' })) - .pause(500) - .perform(); - - const collapse = await textArea().takeScreenshot(); - - await this.expect({ before, addText, collapse }).to.matchImages(); - }, - }, - }, -}; export const TextareaWithCustomWidth = () =>