Skip to content

Commit 122fc0b

Browse files
committed
add stories and tests
1 parent 3495c54 commit 122fc0b

File tree

4 files changed

+202
-17
lines changed

4 files changed

+202
-17
lines changed

packages/ra-ui-materialui/src/input/AutocompleteInput.spec.tsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,6 +1452,50 @@ describe('<AutocompleteInput />', () => {
14521452
expect(input.value).not.toBe('Create x');
14531453
expect(input.value).toBe('x');
14541454
}, 10000);
1455+
1456+
it('should include an option with the custom createLabel when the input is empty and optionText is a string', async () => {
1457+
render(<CreateLabel optionText="full_name" />);
1458+
const input = (await screen.findByLabelText(
1459+
'Author'
1460+
)) as HTMLInputElement;
1461+
input.focus();
1462+
fireEvent.change(input, {
1463+
target: { value: '' },
1464+
});
1465+
const customCreateLabel = screen.queryByText(
1466+
'Start typing to create a new item'
1467+
);
1468+
expect(customCreateLabel).not.toBeNull();
1469+
expect(
1470+
(customCreateLabel as HTMLElement).getAttribute('aria-disabled')
1471+
).toEqual('true');
1472+
expect(screen.queryByText(/Create/)).toBeNull();
1473+
});
1474+
1475+
it('should include an option with the custom createLabel when the input is empty and optionText is a function', async () => {
1476+
render(
1477+
<CreateLabel
1478+
optionText={choice =>
1479+
`${choice.first_name} ${choice.last_name}`
1480+
}
1481+
/>
1482+
);
1483+
const input = (await screen.findByLabelText(
1484+
'Author'
1485+
)) as HTMLInputElement;
1486+
input.focus();
1487+
fireEvent.change(input, {
1488+
target: { value: '' },
1489+
});
1490+
const customCreateLabel = screen.queryByText(
1491+
'Start typing to create a new item'
1492+
);
1493+
expect(customCreateLabel).not.toBeNull();
1494+
expect(
1495+
(customCreateLabel as HTMLElement).getAttribute('aria-disabled')
1496+
).toEqual('true');
1497+
expect(screen.queryByText(/Create/)).toBeNull();
1498+
});
14551499
});
14561500
describe('create', () => {
14571501
it('should allow the creation of a new choice', async () => {

packages/ra-ui-materialui/src/input/AutocompleteInput.stories.tsx

Lines changed: 75 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -258,12 +258,48 @@ export const OptionTextElement = () => (
258258
</Wrapper>
259259
);
260260

261-
const choicesForCreationSupport = [
262-
{ id: 1, name: 'Leo Tolstoy' },
263-
{ id: 2, name: 'Victor Hugo' },
264-
{ id: 3, name: 'William Shakespeare' },
265-
{ id: 4, name: 'Charles Baudelaire' },
266-
{ id: 5, name: 'Marcel Proust' },
261+
const choicesForCreationSupport: Partial<{
262+
id: number;
263+
name: string;
264+
full_name: string;
265+
first_name: string;
266+
last_name: string;
267+
}>[] = [
268+
{
269+
id: 1,
270+
name: 'Leo Tolstoy',
271+
full_name: 'Leo Tolstoy',
272+
first_name: 'Leo',
273+
last_name: 'Tolstoy',
274+
},
275+
{
276+
id: 2,
277+
name: 'Victor Hugo',
278+
full_name: 'Victor Hugo',
279+
first_name: 'Victor',
280+
last_name: 'Hugo',
281+
},
282+
{
283+
id: 3,
284+
name: 'William Shakespeare',
285+
full_name: 'William Shakespeare',
286+
first_name: 'William',
287+
last_name: 'Shakespeare',
288+
},
289+
{
290+
id: 4,
291+
name: 'Charles Baudelaire',
292+
full_name: 'Charles Baudelaire',
293+
first_name: 'Charles',
294+
last_name: 'Baudelaire',
295+
},
296+
{
297+
id: 5,
298+
name: 'Marcel Proust',
299+
full_name: 'Marcel Proust',
300+
first_name: 'Marcel',
301+
last_name: 'Proust',
302+
},
267303
];
268304

269305
const OnCreateInput = () => {
@@ -450,7 +486,7 @@ export const CreateDialog = () => (
450486
</Wrapper>
451487
);
452488

453-
const CreateLabelInput = () => {
489+
const CreateLabelInput = ({ optionText }) => {
454490
const [choices, setChoices] = useState(choicesForCreationSupport);
455491
return (
456492
<AutocompleteInput
@@ -459,25 +495,53 @@ const CreateLabelInput = () => {
459495
onCreate={async filter => {
460496
if (!filter) return;
461497

462-
const newOption = {
498+
const newOption: Partial<{
499+
id: number;
500+
name: string;
501+
full_name: string;
502+
first_name: string;
503+
last_name: string;
504+
}> = {
463505
id: choices.length + 1,
464-
name: filter,
465506
};
507+
if (optionText == null) {
508+
newOption.name = filter;
509+
} else if (typeof optionText === 'string') {
510+
newOption[optionText] = filter;
511+
} else {
512+
newOption.first_name = filter;
513+
newOption.last_name = filter;
514+
}
466515
setChoices(options => [...options, newOption]);
467516
// Wait until next tick to give some time for React to update the state
468517
await new Promise(resolve => setTimeout(resolve));
469518
return newOption;
470519
}}
471520
createLabel="Start typing to create a new item"
521+
optionText={optionText}
472522
/>
473523
);
474524
};
475525

476-
export const CreateLabel = () => (
526+
export const CreateLabel = ({ optionText }: any) => (
477527
<Wrapper>
478-
<CreateLabelInput />
528+
<CreateLabelInput optionText={optionText} />
479529
</Wrapper>
480530
);
531+
CreateLabel.args = {
532+
optionText: undefined,
533+
};
534+
CreateLabel.argTypes = {
535+
optionText: {
536+
options: ['default', 'string', 'function'],
537+
mapping: {
538+
default: undefined,
539+
string: 'full_name',
540+
function: choice => `${choice.first_name} ${choice.last_name}`,
541+
},
542+
control: { type: 'inline-radio' },
543+
},
544+
};
481545

482546
const CreateItemLabelInput = () => {
483547
const [choices, setChoices] = useState(choicesForCreationSupport);

packages/ra-ui-materialui/src/input/SelectInput.spec.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,46 @@ describe('<SelectInput />', () => {
697697
});
698698
promptSpy.mockRestore();
699699
});
700+
701+
it('should support using a custom createLabel with optionText being a string', async () => {
702+
const promptSpy = jest.spyOn(window, 'prompt');
703+
promptSpy.mockImplementation(jest.fn(() => 'New Category'));
704+
render(<CreateLabel optionText="full_name" />);
705+
const input = (await screen.findByLabelText(
706+
'Category'
707+
)) as HTMLInputElement;
708+
fireEvent.mouseDown(input);
709+
// Expect the custom create label to be displayed
710+
fireEvent.click(await screen.findByText('Create a new category'));
711+
// Expect a prompt to have opened
712+
await waitFor(() => {
713+
expect(promptSpy).toHaveBeenCalled();
714+
});
715+
promptSpy.mockRestore();
716+
});
717+
718+
it('should support using a custom createLabel with optionText being a function', async () => {
719+
const promptSpy = jest.spyOn(window, 'prompt');
720+
promptSpy.mockImplementation(jest.fn(() => 'New Category'));
721+
render(
722+
<CreateLabel
723+
optionText={choice =>
724+
`${choice.full_name} (${choice.language})`
725+
}
726+
/>
727+
);
728+
const input = (await screen.findByLabelText(
729+
'Category'
730+
)) as HTMLInputElement;
731+
fireEvent.mouseDown(input);
732+
// Expect the custom create label to be displayed
733+
fireEvent.click(await screen.findByText('Create a new category'));
734+
// Expect a prompt to have opened
735+
await waitFor(() => {
736+
expect(promptSpy).toHaveBeenCalled();
737+
});
738+
promptSpy.mockRestore();
739+
});
700740
});
701741

702742
it('should support creation of a new choice through the create element', async () => {

packages/ra-ui-materialui/src/input/SelectInput.stories.tsx

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -321,31 +321,68 @@ export const OnCreate = () => {
321321
);
322322
};
323323

324-
export const CreateLabel = () => {
325-
const categories = [
326-
{ name: 'Tech', id: 'tech' },
327-
{ name: 'Lifestyle', id: 'lifestyle' },
324+
export const CreateLabel = ({ optionText }: any) => {
325+
const categories: Partial<{
326+
id: string;
327+
name: string;
328+
full_name: string;
329+
language: string;
330+
}>[] = [
331+
{ id: 'tech', name: 'Tech', full_name: 'Tech', language: 'en' },
332+
{
333+
id: 'lifestyle',
334+
name: 'Lifestyle',
335+
full_name: 'Lifestyle',
336+
language: 'en',
337+
},
328338
];
329339
return (
330340
<Wrapper name="category">
331341
<SelectInput
332342
onCreate={() => {
333343
const newCategoryName = prompt('Enter a new category');
334344
if (!newCategoryName) return;
335-
const newCategory = {
345+
const newCategory: Partial<{
346+
id: string;
347+
name: string;
348+
full_name: string;
349+
language: string;
350+
}> = {
336351
id: newCategoryName.toLowerCase(),
337-
name: newCategoryName,
338352
};
353+
if (optionText == null) {
354+
newCategory.name = newCategoryName;
355+
} else if (typeof optionText === 'string') {
356+
newCategory[optionText] = newCategoryName;
357+
} else {
358+
newCategory.full_name = newCategoryName;
359+
newCategory.language = 'fr';
360+
}
339361
categories.push(newCategory);
340362
return newCategory;
341363
}}
342364
source="category"
343365
choices={categories}
344366
createLabel="Create a new category"
367+
optionText={optionText}
345368
/>
346369
</Wrapper>
347370
);
348371
};
372+
CreateLabel.args = {
373+
optionText: undefined,
374+
};
375+
CreateLabel.argTypes = {
376+
optionText: {
377+
options: ['default', 'string', 'function'],
378+
mapping: {
379+
default: undefined,
380+
string: 'full_name',
381+
function: choice => `${choice.full_name} (${choice.language})`,
382+
},
383+
control: { type: 'inline-radio' },
384+
},
385+
};
349386

350387
const i18nProvider = polyglotI18nProvider(() => englishMessages);
351388

0 commit comments

Comments
 (0)