Skip to content

Commit

Permalink
Bal 1740 - E2E Test Ids (#2249)
Browse files Browse the repository at this point in the history
* feat: added test ids to inputs & dynamic form adapters & updated storybook

* feat: added missing test ids & ui bump

* fix: added test id to form & renamed story

* fix: added names to json forms in seed & added test id to json form

* fix: fixed kyb tests & renamed data-test-id -> data-testid

* fix: added WithTestId ts util & refactored props

* chore(gh-actions): test

---------

Co-authored-by: Alon Peretz <Alonp99@gmail.com>
  • Loading branch information
chesterkmr and alonp99 committed Mar 31, 2024
1 parent 30323c6 commit 4a56ffb
Show file tree
Hide file tree
Showing 49 changed files with 236 additions and 56 deletions.
7 changes: 7 additions & 0 deletions apps/kyb-app/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# kyb-app

## 0.3.3

### Patch Changes

- Updated dependencies
- @ballerine/ui@0.5.2

## 0.3.2

### Patch Changes
Expand Down
4 changes: 2 additions & 2 deletions apps/kyb-app/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@ballerine/kyb-app",
"private": true,
"version": "0.3.2",
"version": "0.3.3",
"type": "module",
"scripts": {
"dev": "vite",
Expand All @@ -16,7 +16,7 @@
"dependencies": {
"@ballerine/blocks": "0.2.2",
"@ballerine/common": "^0.9.1",
"@ballerine/ui": "0.5.1",
"@ballerine/ui": "0.5.2",
"@ballerine/workflow-browser-sdk": "0.6.3",
"@lukemorales/query-key-factory": "^1.0.3",
"@radix-ui/react-icons": "^1.3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ import { DefinitionInsertionParams } from '@/components/organisms/UIRenderer/hoo
import { useUIElementErrors } from '@/components/organisms/UIRenderer/hooks/useUIElementErrors/useUIElementErrors';
import { useUIElementProps } from '@/components/organisms/UIRenderer/hooks/useUIElementProps';
import { useUIElementState } from '@/components/organisms/UIRenderer/hooks/useUIElementState';
import { Rule } from '@/domains/collection-flow';
import { CollectionFlowContext } from '@/domains/collection-flow/types/flow-context.types';
import { transformRJSFErrors } from '@/helpers/transform-errors';
import { AnyObject, DynamicForm, ErrorsList } from '@ballerine/ui';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import get from 'lodash/get';
import set from 'lodash/set';
import { useCallback, useEffect, useMemo, useRef } from 'react';
import { Rule } from '@/domains/collection-flow';

export interface JSONFormElementBaseParams extends DefinitionInsertionParams {
jsonFormDefinition: RJSFSchema;
Expand Down Expand Up @@ -95,6 +95,7 @@ export const JSONForm: UIElementComponent<JSONFormElementBaseParams> = ({ defini
layouts={jsonFormLayouts}
formData={formData}
ref={formRef}
testId={definition?.name ? `${definition.name}` : undefined}
transformErrors={transformRJSFErrors}
onSubmit={handleSubmit}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
import { Checkbox, RJSFInputProps, ctw } from '@ballerine/ui';
import { Checkbox, RJSFInputProps, WithTestId, ctw } from '@ballerine/ui';
import { useMemo } from 'react';

interface CheckboxListOption {
title: string;
value: string;
}

export const CheckboxList = (props: RJSFInputProps) => {
export const CheckboxList = (props: WithTestId<RJSFInputProps>) => {
//@ts-nocheck
const { uiSchema, formData = [], onChange, disabled } = props;
const { uiSchema, formData = [], onChange, disabled, testId } = props;

const options = useMemo(() => {
return (uiSchema?.['options'] as CheckboxListOption[]) || [];
}, [uiSchema]);

return (
<div className={ctw('flex flex-col gap-4', { 'pointer-events-none opacity-50': disabled })}>
<div
className={ctw('flex flex-col gap-4', { 'pointer-events-none opacity-50': disabled })}
data-testid={testId}
>
{options.map(option => (
<label className="flex items-center gap-2" key={option.value}>
<Checkbox
className="border-secondary data-[state=checked]:bg-secondary data-[state=checked]:text-secondary-foreground bg-white"
color="primary"
value={option.value}
checked={Array.isArray(formData) && formData.includes(option.value)}
data-testid={testId ? `${testId}-checkbox` : undefined}
onCheckedChange={checked => {
let value = (formData as string[]) || [];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ export const DocumentField = (
fileId={fileId}
fileRepository={collectionFlowFileStorage}
onBlur={onBlur as () => void}
testId={definition.name}
onChange={handleChange}
/>
{!!warnings.length && <ErrorsList errors={warnings.map(err => err.message)} />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const FileUploaderField = ({
disabled,
acceptFileFormats,
placeholder,
testId,
}: DocumentUploadFieldProps) => {
const { isUploading, uploadFile } = useFileUploading(_uploadFile);
const { file: registeredFile, registerFile } = useFileRepository(
Expand Down Expand Up @@ -42,7 +43,7 @@ export const FileUploaderField = ({

return (
<Input
data-testid="file-uploader-field"
data-testid={testId}
type="file"
placeholder={placeholder}
accept={acceptFileFormats}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ describe('FileUploaderField', () => {
uploadFile={() => Promise.resolve({ fileId: '123' })}
onChange={() => {}}
fileRepository={new FileRepository()}
testId="file-uploader-field"
/>,
);
getByTestId('file-uploader-field');
Expand All @@ -52,6 +53,7 @@ describe('FileUploaderField', () => {
placeholder={testPlaceholder}
onChange={() => {}}
fileRepository={new FileRepository()}
testId="file-uploader-field"
/>,
);

Expand All @@ -67,6 +69,7 @@ describe('FileUploaderField', () => {
acceptFileFormats={testFileFormats}
onChange={() => {}}
fileRepository={new FileRepository()}
testId="file-uploader-field"
/>,
);

Expand All @@ -81,6 +84,7 @@ describe('FileUploaderField', () => {
onChange={() => {}}
fileRepository={new FileRepository()}
isLoading={true}
testId="file-uploader-field"
/>,
);

Expand All @@ -94,6 +98,7 @@ describe('FileUploaderField', () => {
onChange={() => {}}
fileRepository={new FileRepository()}
disabled={true}
testId="file-uploader-field"
/>,
);

Expand All @@ -106,6 +111,7 @@ describe('FileUploaderField', () => {
uploadFile={() => Promise.resolve({ fileId: '123' })}
onChange={() => {}}
fileRepository={new FileRepository()}
testId="file-uploader-field"
/>,
);

Expand All @@ -131,6 +137,7 @@ describe('FileUploaderField', () => {
uploadFile={() => Promise.resolve({ fileId: '123' })}
onChange={onChangeCallback}
fileRepository={new FileRepository()}
testId="file-uploader-field"
/>,
);

Expand All @@ -157,6 +164,7 @@ describe('FileUploaderField', () => {
onBlur={onBlurCallaback}
onChange={onChangeCallback}
fileRepository={new FileRepository()}
testId="file-uploader-field"
/>,
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ export interface DocumentUploadFieldProps {
disabled?: boolean;
acceptFileFormats?: string;
placeholder?: string;
testId?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ import { useStateManagerContext } from '@/components/organisms/DynamicUI/StateMa
import { JsonLogicRuleEngine } from '@/components/organisms/DynamicUI/rule-engines';
import { useJSONFormDefinition } from '@/components/organisms/UIRenderer/elements/JSONForm/providers/JSONFormDefinitionProvider/useJSONFormDefinition';
import { ArrayInsertionStrategy } from '@/components/organisms/UIRenderer/hooks/useDataInsertionLogic/insert-strategies/array.insertion-strategy';
import { useUIElementHandlers } from '@/components/organisms/UIRenderer/hooks/useUIElementHandlers';
import {
AnyObject,
ArrayFieldsLayout,
ArrayFieldsLayoutItem,
ArrayFieldsLayoutItemTitle,
ArrayFieldsLayoutProps,
} from '@ballerine/ui';
import React, { useCallback, useMemo } from 'react';
import pullAt from 'lodash/pullAt';
import get from 'lodash/get';
import pullAt from 'lodash/pullAt';
import set from 'lodash/set';
import React, { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useUIElementHandlers } from '@/components/organisms/UIRenderer/hooks/useUIElementHandlers';

const jsonLogicRuleEngine = new JsonLogicRuleEngine();

Expand Down Expand Up @@ -90,6 +90,7 @@ export const JSONFormArrayFieldLayout = (props: ArrayFieldsLayoutProps) => {
(item?.children?.props as AnyObject)?.formData || {},
definition.options?.insertionParams?.bindingAnchorDestination,
)}
testId={`${definition.name}-item[${index}]`}
/>
))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export type DynamicUIComponent<TProps, TParams = AnyObject> = React.ComponentTyp
>;

export const withDynamicUIInput = (
Component: RJSFInputAdapter<any, any> & { inputIndex?: number | null },
Component: RJSFInputAdapter<any, any> & { inputIndex?: number | null; testId?: string },
) => {
function Wrapper(props: RJSFInputProps) {
const inputId = (props.idSchema as AnyObject)?.$id as string;
Expand Down Expand Up @@ -128,12 +128,16 @@ export const withDynamicUIInput = (
formData={value}
definition={definition}
inputIndex={inputIndex}
testId={definition.name}
onChange={handleChange}
onBlur={handleBlur}
/>
{!!warnings.length && <ErrorsList errors={warnings.map(err => err.message)} />}
{isTouched && !!validationErrors.length && (
<ErrorsList errors={validationErrors.map(error => error.message)} />
<ErrorsList
testId={definition.name}
errors={validationErrors.map(error => error.message)}
/>
)}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export const SubmitButton: UIElementComponent<{ text: string }> = ({ definition
variant="secondary"
onClick={handleClick}
disabled={state.isLoading || uiElementState.isLoading}
data-testid={definition.name}
>
{definition.options.text || 'Submit'}
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const Task = ({ options = {}, childrens, ...rest }: TaskProps) => {
const Component = variant === 'wrapper' ? Card : 'div';

return (
<Component className={className} style={styles} data-test-id="task">
<Component className={className} style={styles} data-testid="task">
<BlocksComponent
Block={
// @ts-ignore
Expand Down
7 changes: 7 additions & 0 deletions packages/react-pdf-toolkit/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# @ballerine/react-pdf-toolkit

## 1.2.2

### Patch Changes

- Updated dependencies
- @ballerine/ui@0.5.2

## 1.2.1

### Patch Changes
Expand Down
4 changes: 2 additions & 2 deletions packages/react-pdf-toolkit/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@ballerine/react-pdf-toolkit",
"private": false,
"version": "1.2.1",
"version": "1.2.2",
"types": "./dist/build.d.ts",
"main": "./dist/react-pdf-toolkit.js",
"module": "./dist/react-pdf-toolkit.mjs",
Expand All @@ -27,7 +27,7 @@
},
"dependencies": {
"@ballerine/config": "^1.1.2",
"@ballerine/ui": "0.5.1",
"@ballerine/ui": "0.5.2",
"@react-pdf/renderer": "^3.1.14",
"@sinclair/typebox": "^0.31.7",
"ajv": "^8.12.0",
Expand Down
6 changes: 6 additions & 0 deletions packages/ui/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @ballerine/ui

## 0.5.2

### Patch Changes

- Added test ids to inputs

## 0.5.1

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@ballerine/ui",
"private": false,
"version": "0.5.1",
"version": "0.5.2",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ import { ReactNode } from 'react';
export type ChildrenList = ReactNode[];
export type AnyChildren = ReactNode | ChildrenList;
export type AnyObject = Record<PropertyKey, any>;
export type WithTestId<TParams> = { testId?: string } & TParams;
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { WithTestId } from '@/common';
import clsx from 'clsx';
import styles from './PhoneNumberInput.module.scss';
import PhoneInput, { PhoneInputProps } from 'react-phone-input-2';
import 'react-phone-input-2/lib/style.css';
import styles from './PhoneNumberInput.module.scss';

export type PhoneInputStylesPropsNames =
| 'inputClass'
Expand All @@ -16,10 +17,10 @@ export type PhoneInputStylesPropsNames =

export type PhoneInputPropsWithoutStyleProps = Omit<PhoneInputProps, PhoneInputStylesPropsNames>;

export type PhoneNumberInputProps = PhoneInputPropsWithoutStyleProps;
export type PhoneNumberInputProps = WithTestId<PhoneInputPropsWithoutStyleProps>;

export const PhoneNumberInput = (props: PhoneNumberInputProps) => {
const { disableSearchIcon = true, disabled, ...restProps } = props;
const { disableSearchIcon = true, disabled, testId, ...restProps } = props;

return (
<PhoneInput
Expand All @@ -29,6 +30,7 @@ export const PhoneNumberInput = (props: PhoneNumberInputProps) => {
containerClass="flex items-center border border-input h-9 focus-within:ring-ring focus-within:ring-1 rounded-md font-inter disabled:cursor-not-allowed disabled:opacity-50"
inputClass="w-full h-8 border-none outline-none disabled:cursor-not-allowed disabled:opacity-50"
searchClass={styles.searchInput}
inputProps={{ ...restProps.inputProps, 'data-testid': testId }}
buttonClass={clsx(
'border-none rounded-l-md',
{ 'cursor-not-allowed opacity-50': disabled },
Expand Down
13 changes: 10 additions & 3 deletions packages/ui/src/components/molecules/ErrorsList/ErrorsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,20 @@ interface Props {
errors: string[];
type?: 'error' | 'warning';
className?: string;
testId?: string;
}

export const ErrorsList = ({ errors, type = 'error', className }: Props) => {
export const ErrorsList = ({ errors, type = 'error', className, testId }: Props) => {
return (
<ul className={clsx('pl-1', className)}>
<ul
className={clsx('pl-1', className)}
data-testid={testId ? `${testId}-errors-list` : undefined}
>
{errors.map((error, index) => (
<li key={`error-list-item-${index}`}>
<li
key={`error-list-item-${index}`}
data-testid={testId ? `${testId}-error-list-item-${index}` : undefined}
>
<ErrorMessage
text={error}
className={type === 'warning' ? 'text-amber-400' : undefined}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,13 @@ export const Controlled = {
export const Disabled = {
render: () => <AutocompleteInput disabled options={[]} onChange={() => {}} />,
};

export const WithTestId = {
render: () => (
<AutocompleteInput
options={storyOptions}
onChange={() => {}}
testId="autocomplete-input-test-id"
/>
),
};

0 comments on commit 4a56ffb

Please sign in to comment.