Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Create Selector function #49

Merged
merged 6 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Change Log

## 2.7.0 (IN PROGRESS)

### Features

- Update to use auto-apply selectors (#49)

## 2.6.0 (2024-06-12)

### Features
Expand Down
2 changes: 1 addition & 1 deletion packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"@emotion/css": "^11.11.2",
"@grafana/data": "^11.1.0",
"@grafana/ui": "^11.1.0",
"@volkovlabs/jest-selectors": "^1.4.1",
"classnames": "^2.5.1",
"rc-slider": "^10.5.0",
"rc-tooltip": "^6.2.0"
Expand All @@ -30,7 +31,6 @@
"@types/node": "^20.9.1",
"@typescript-eslint/eslint-plugin": "^6.11.0",
"@volkovlabs/eslint-config": "^1.0.0",
"@volkovlabs/jest-selectors": "^1.2.0",
"css-loader": "^6.8.1",
"esbuild": "^0.19.5",
"eslint": "^8.53.0",
Expand Down
2 changes: 2 additions & 0 deletions packages/components/rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default [
'@grafana/data',
'lodash',
'rc-slider/assets/index.css',
'@volkovlabs/jest-selectors',
],
},
{
Expand All @@ -45,6 +46,7 @@ export default [
'@grafana/data',
'lodash',
'rc-slider/assets/index.css',
'@volkovlabs/jest-selectors',
],
},
];
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { fireEvent, render, screen } from '@testing-library/react';
import { getJestSelectors } from '@volkovlabs/jest-selectors';
import { getJestSelectors, createSelector } from '@volkovlabs/jest-selectors';
import React from 'react';

import { CODE_EDITOR_CONFIG } from '../../constants';
Expand All @@ -14,7 +14,7 @@ type Props = React.ComponentProps<typeof AutosizeCodeEditor>;
* In Test Ids
*/
const InTestIds = {
field: 'data-testid field',
field: createSelector('data-testid field'),
};

/**
Expand All @@ -24,7 +24,7 @@ jest.mock('@grafana/ui', () => ({
...jest.requireActual('@grafana/ui'),
CodeEditor: jest.fn(({ value, onChange, height }) => (
<textarea
data-testid={InTestIds.field}
{...InTestIds.field.apply()}
style={{ height }}
value={value}
onChange={(event) => onChange(event.currentTarget.value)}
Expand Down
16 changes: 10 additions & 6 deletions packages/components/src/components/Collapse/Collapse.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { fireEvent, render, screen } from '@testing-library/react';
import { getJestSelectors } from '@volkovlabs/jest-selectors';
import { getJestSelectors, createSelector } from '@volkovlabs/jest-selectors';
import React from 'react';

import { Collapse } from './Collapse';
Expand All @@ -10,9 +10,9 @@ type Props = React.ComponentProps<typeof Collapse>;
* In Test Ids
*/
const InTestIds = {
header: 'data-testid header',
content: 'data-testid content',
buttonRemove: 'data-testid button-remove',
header: createSelector('data-testid header', 'headerTestId'),
content: createSelector('data-testid content', 'contentTestId'),
buttonRemove: createSelector('data-testid button-remove'),
};

/**
Expand All @@ -27,7 +27,7 @@ describe('Collapse', () => {
* Get Tested Component
*/
const getComponent = (props: Partial<Props>) => {
return <Collapse headerTestId={InTestIds.header} contentTestId={InTestIds.content} {...props} />;
return <Collapse {...InTestIds.header.apply()} {...InTestIds.content.apply()} {...props} />;
};

it('Should expand content', () => {
Expand All @@ -42,7 +42,11 @@ describe('Collapse', () => {
it('Actions should not affect collapse state', () => {
const onToggle = jest.fn();

render(getComponent({ onToggle, actions: <button data-testid={InTestIds.buttonRemove}>remove</button> }));
/**
* New
*/
render(getComponent({ onToggle, actions: <button {...InTestIds.buttonRemove.apply()}>remove</button> }));

fireEvent.click(selectors.buttonRemove());
expect(onToggle).not.toHaveBeenCalled();
});
Expand Down
33 changes: 13 additions & 20 deletions packages/components/src/components/Form/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ export const Form = <TValue extends object>({
<CollapsableSection
key={field.fullPath}
label={field.label}
headerDataTestId={TEST_IDS.form.sectionHeader(field.fullPath)}
contentDataTestId={TEST_IDS.form.sectionContent(field.fullPath)}
{...TEST_IDS.form.sectionHeader.apply(field.fullPath)}
{...TEST_IDS.form.sectionContent.apply(field.fullPath)}
contentClassName={styles.section}
isOpen={expanded[field.fullPath] ?? true}
onToggle={(isOpen) =>
Expand Down Expand Up @@ -204,7 +204,7 @@ export const Form = <TValue extends object>({
}
}}
{...field.settings}
aria-label={TEST_IDS.form.fieldSelect(field.fullPath)}
{...TEST_IDS.form.fieldSelect.apply(field.fullPath)}
/>
</FieldComponent>
);
Expand All @@ -214,11 +214,7 @@ export const Form = <TValue extends object>({
const Editor = field.editor;
return (
<FieldComponent {...fieldProps}>
<Editor
value={field.value}
onChange={field.onChange}
data-testid={TEST_IDS.form.fieldCustom(field.fullPath)}
/>
<Editor value={field.value} onChange={field.onChange} {...TEST_IDS.form.fieldCustom.apply(field.fullPath)} />
</FieldComponent>
);
}
Expand All @@ -233,7 +229,7 @@ export const Form = <TValue extends object>({
max={field.max}
step={field.step}
marks={field.marks}
data-testid={TEST_IDS.form.fieldSlider(field.fullPath)}
{...TEST_IDS.form.fieldSlider.apply(field.fullPath)}
/>
</FieldComponent>
);
Expand All @@ -249,7 +245,7 @@ export const Form = <TValue extends object>({
max={field.max}
step={field.step}
marks={field.marks}
sliderAriaLabel={TEST_IDS.form.fieldRangeSlider(field.fullPath)}
{...TEST_IDS.form.fieldRangeSlider.apply(field.fullPath)}
/>
</FieldComponent>
);
Expand All @@ -264,7 +260,7 @@ export const Form = <TValue extends object>({
min={field.min}
max={field.max}
step={field.step}
data-testid={TEST_IDS.form.fieldNumberInput(field.fullPath)}
{...TEST_IDS.form.fieldNumberInput.apply(field.fullPath)}
/>
</FieldComponent>
);
Expand All @@ -281,7 +277,7 @@ export const Form = <TValue extends object>({
field.onChange(color);
}
}}
data-testid={TEST_IDS.form.fieldColor(field.fullPath)}
{...TEST_IDS.form.fieldColor.apply(field.fullPath)}
/>
</FormControl>
</FieldComponent>
Expand All @@ -297,7 +293,7 @@ export const Form = <TValue extends object>({
field.onChange(event.currentTarget.value);
}}
placeholder={field.placeholder}
data-testid={TEST_IDS.form.fieldInput(field.fullPath)}
{...TEST_IDS.form.fieldInput.apply(field.fullPath)}
/>
</FieldComponent>
);
Expand All @@ -308,10 +304,7 @@ export const Form = <TValue extends object>({
return (
<FieldComponent {...fieldProps}>
{fieldProps.disabled ? (
<Input
value={dateTimeFormat(dateTime(field.value), { format })}
data-testid={TEST_IDS.form.fieldDatetime()}
/>
<Input value={dateTimeFormat(dateTime(field.value), { format })} {...TEST_IDS.form.fieldDatetime.apply()} />
) : (
<DateTimePicker
minDate={field.min ? new Date(field.min) : undefined}
Expand All @@ -323,7 +316,7 @@ export const Form = <TValue extends object>({
field.onChange(value.toISOString());
}
}}
data-testid={TEST_IDS.form.fieldDatetime()}
{...TEST_IDS.form.fieldDatetime.apply()}
/>
)}
</FieldComponent>
Expand All @@ -332,7 +325,7 @@ export const Form = <TValue extends object>({

if (field.type === FormFieldType.RADIO) {
return (
<FieldComponent {...fieldProps} data-testid={TEST_IDS.form.fieldRadio(field.fullPath)}>
<FieldComponent {...fieldProps} {...TEST_IDS.form.fieldRadio.apply(field.fullPath)}>
<RadioButtonGroup
value={field.value}
onChange={field.onChange}
Expand All @@ -348,7 +341,7 @@ export const Form = <TValue extends object>({
};

return (
<div data-testid={TEST_IDS.form.root(name)}>
<div {...TEST_IDS.form.root.apply(name)}>
{groupFieldsInRows(fields).map((fields, index) =>
fields.length > 1 && variant === 'inline' ? (
<InlineFieldRow key={index}>{fields.map((field) => renderField(field))}</InlineFieldRow>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { fireEvent, render, screen } from '@testing-library/react';
import { getJestSelectors } from '@volkovlabs/jest-selectors';
import { getJestSelectors, createSelector } from '@volkovlabs/jest-selectors';
import React from 'react';

import { NumberInput } from './NumberInput';
Expand All @@ -13,7 +13,7 @@ type Props = React.ComponentProps<typeof NumberInput>;
* In Test Ids
*/
const InTestIds = {
field: 'data-testid field',
field: createSelector('data-testid field'),
};

describe('Number Input', () => {
Expand All @@ -27,7 +27,7 @@ describe('Number Input', () => {
* Get Component
*/
const getComponent = (props: Partial<Props>) => {
return <NumberInput min={1} max={10} data-testid={InTestIds.field} {...(props as any)} />;
return <NumberInput min={1} max={10} {...InTestIds.field.apply()} {...(props as any)} />;
};

it('Should allow to enter negative value', () => {
Expand Down
26 changes: 14 additions & 12 deletions packages/components/src/constants/tests.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
import { createSelector } from '@volkovlabs/jest-selectors';

/**
* Test Identifiers
*/
export const TEST_IDS = {
form: {
root: (name: unknown) => `data-testid form-${name}`,
sectionHeader: (name: unknown) => `data-testid form section-${name}`,
sectionContent: (name: unknown) => `data-testid form section-content-${name}`,
fieldSelect: (name: unknown) => `form field-select-${name}`,
fieldCustom: (name: unknown) => `data-testid form field-custom-${name}`,
fieldSlider: (name: unknown) => `data-testid form field-slider-${name}`,
fieldRangeSlider: (name: unknown) => `form field-range-slider-${name}`,
fieldNumberInput: (name: unknown) => `data-testid form field-number-input-${name}`,
fieldColor: (name: unknown) => `data-testid form field-color-${name}`,
fieldInput: (name: unknown) => `data-testid form field-input-${name}`,
root: createSelector((name: unknown) => `data-testid form-${name}`),
sectionHeader: createSelector((name: unknown) => `data-testid form section-${name}`, 'headerDataTestId'),
sectionContent: createSelector((name: unknown) => `data-testid form section-content-${name}`, 'contentDataTestId'),
fieldSelect: createSelector((name: unknown) => `form field-select-${name}`),
fieldCustom: createSelector((name: unknown) => `data-testid form field-custom-${name}`),
fieldSlider: createSelector((name: unknown) => `data-testid form field-slider-${name}`),
fieldRangeSlider: createSelector((name: unknown) => `form field-range-slider-${name}`, 'sliderAriaLabel'),
fieldNumberInput: createSelector((name: unknown) => `data-testid form field-number-input-${name}`),
fieldColor: createSelector((name: unknown) => `data-testid form field-color-${name}`),
fieldInput: createSelector((name: unknown) => `data-testid form field-input-${name}`),
/**
* We should use default value for date-time-picker without data-testid prefix
* https://github.com/grafana/grafana/blob/f43762f39abad43f99b85cbcff6ca30c56f9d75f/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.tsx#L249
*/
fieldDatetime: () => `data-testid date-time-input`,
fieldRadio: (name: unknown) => `data-testid form field-radio-${name}`,
fieldDatetime: createSelector(() => `data-testid date-time-input`),
fieldRadio: createSelector((name: unknown) => `data-testid form field-radio-${name}`),
},
};
6 changes: 6 additions & 0 deletions packages/jest-selectors/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Change Log

## 1.4.1 (2024-07-01)

### Features / Enhancements

- Add createSelector function (#49)

## 1.3.0 (2024-05-02)

### Features / Enhancements
Expand Down
2 changes: 1 addition & 1 deletion packages/jest-selectors/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,5 @@
"typecheck": "tsc --emitDeclarationOnly false --noEmit"
},
"types": "dist/index.d.ts",
"version": "1.3.0"
"version": "1.4.1"
}
21 changes: 20 additions & 1 deletion packages/jest-selectors/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,28 @@ type JestSelector<TArgs extends unknown[]> = (
...args: TArgs
) => ReturnType<GetByBoundAttribute>;

/**
* Check If Selector Object
*/
type IsSelectorObject<TCandidate> = TCandidate extends {
selector: (...args: unknown[]) => void;
apply: (...args: unknown[]) => void;
}
? TCandidate & { selector: TCandidate['selector']; apply: TCandidate['apply'] }
: never;

/**
* Jest Selectors
*/
export type JestSelectors<T> = {
[K in keyof T]: T[K] extends (...args: infer Args) => void ? JestSelector<Args> : JestSelector<[]>;
[K in keyof T]: T[K] extends (...args: infer Args) => void
? JestSelector<Args>
: T[K] extends IsSelectorObject<T[K]>
? JestSelector<Parameters<T[K]['selector']>>
: JestSelector<[]>;
};

/**
* Selector Function
*/
export type SelectorFn = (...args: unknown[]) => string;
Loading
Loading