Skip to content

Commit

Permalink
Merge pull request #18135 from evont/fix-avoid-undefined-args
Browse files Browse the repository at this point in the history
Controls: Fix undefined args handling
  • Loading branch information
shilman committed May 5, 2022
2 parents 305cb2b + 1ab2149 commit 973d335
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 7 deletions.
20 changes: 20 additions & 0 deletions examples/official-storybook/stories/core/args.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,23 @@ DifferentSet.args = {
foo: 'bar',
bar: 2,
};

export const TestUndefinedArgs = Template.bind({});
TestUndefinedArgs.args = {
first: 'Bob',
last: 'Miller',
foo: 'bar',
};
TestUndefinedArgs.argTypes = {
first: {
control: { type: 'select' },
options: ['Bob', 'Alice'],
},
last: {
control: { type: 'select' },
options: ['Miller', 'Meyer'],
},
foo: {
control: { type: 'text' },
},
};
5 changes: 5 additions & 0 deletions lib/store/src/args.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,11 @@ describe('validateOptions', () => {
expect(validateOptions({ a: 1 }, { a: { options: [1, 2] } })).toStrictEqual({ a: 1 });
});

// https://github.com/storybookjs/storybook/issues/17063
it('does not set args to `undefined` if they are unset and there are options', () => {
expect(validateOptions({}, { a: { options: [2, 3] } })).toStrictEqual({});
});

it('includes arg if value is undefined', () => {
expect(validateOptions({ a: undefined }, { a: { options: [1, 2] } })).toStrictEqual({
a: undefined,
Expand Down
16 changes: 9 additions & 7 deletions lib/store/src/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,21 +73,25 @@ export const combineArgs = (value: any, update: any): Args => {

export const validateOptions = (args: Args, argTypes: ArgTypes): Args => {
return Object.entries(argTypes).reduce((acc, [key, { options }]) => {
if (!options) {
// Don't set args that are not defined in `args` (they can be undefined in there)
// see https://github.com/storybookjs/storybook/issues/15630 and
// https://github.com/storybookjs/storybook/issues/17063
function allowArg() {
if (key in args) {
acc[key] = args[key];
}
return acc;
}

if (!options) return allowArg();

if (!Array.isArray(options)) {
once.error(dedent`
Invalid argType: '${key}.options' should be an array.
More info: https://storybook.js.org/docs/react/api/argtypes
`);
acc[key] = args[key];
return acc;
return allowArg();
}

if (options.some((opt) => opt && ['object', 'function'].includes(typeof opt))) {
Expand All @@ -96,17 +100,15 @@ export const validateOptions = (args: Args, argTypes: ArgTypes): Args => {
More info: https://storybook.js.org/docs/react/writing-stories/args#mapping-to-complex-arg-values
`);
acc[key] = args[key];
return acc;
return allowArg();
}

const isArray = Array.isArray(args[key]);
const invalidIndex = isArray && args[key].findIndex((val: any) => !options.includes(val));
const isValidArray = isArray && invalidIndex === -1;

if (args[key] === undefined || options.includes(args[key]) || isValidArray) {
acc[key] = args[key];
return acc;
return allowArg();
}

const field = isArray ? `${key}[${invalidIndex}]` : key;
Expand Down

0 comments on commit 973d335

Please sign in to comment.