The problem
When using the --include CLI flag with npx percy storybook, story-level parameters.percy.skip: true is silently ignored and snapshots are taken anyway. The skip flag works correctly when --include is not used.
Environment
- Node version: v24.13.1
@percy/cli version: 1.31.4
- Version of Percy SDK you’re using: 9.1.0
- If needed, a build or snapshot ID: N/A
- OS version: Ubuntu (GitHub Actions runner)
- Type of shell command-line [interface]: bash
Details
In shouldSkipStory (within the Storybook SDK), when any global filter (config.include or config.exclude) is present, the function switches filter from options (the story) to config (the CLI config):
// if a global filter is present, disregard story filters
let filter = (config?.include || config?.exclude) ? config : options;
...
let skip = include?.length ? !include.some(matches) : options.skip;
Because filter is now config, the include array is built from the CLI flags. When the story name matches an --include pattern, include.some(matches) returns true and skip is set to false — options.skip (parameters.percy.skip: true) is never evaluated.
This means that any story explicitly included via --include can never be skipped at the story level. The comment in the code says "if a global filter is present, disregard story filters", but this also discards the skip flag, which is not a filter — it is an opt-out mechanism independent of inclusion/exclusion logic.
Expected: a story with parameters.percy.skip: true should always be skipped, regardless of whether it was matched by a --include pattern.
Actual: the story is snapshotted.
|
function shouldSkipStory(name, options, config) { |
|
let matches = regexp => { |
|
/* istanbul ignore else: sanity check */ |
|
if (typeof regexp === 'string') { |
|
let [, parsed, flags] = /^\/(.+)\/(\w+)?$/.exec(regexp) || []; |
|
regexp = new RegExp(parsed ?? regexp, flags); |
|
} |
|
|
|
return regexp?.test?.(name); |
|
}; |
|
|
|
// if a global filter is present, disregard story filters |
|
let filter = (config?.include || config?.exclude) ? config : options; |
|
let include = [].concat(filter?.include).filter(Boolean); |
|
let exclude = [].concat(filter?.exclude).filter(Boolean); |
|
|
|
// if included, don't skip; if excluded always exclude |
|
let skip = include?.length ? !include.some(matches) : options.skip; |
|
if (!skip && !exclude?.some(matches)) return false; |
|
return true; |
|
} |
Suggested fix:
let skip = include?.length ? !include.some(matches) : false;
if (!skip && options.skip) skip = true; // always honour story-level skip
Debug logs
N/A — the behaviour is deterministic and the root cause is identified directly in the source.
Code to reproduce issue
Story file:
// component.stories.tsx
export const Default: Story = {
parameters: { percy: { skip: true } },
render: ...,
};
Percy invocation:
npx percy storybook ./dist/storybook --include "Atoms/Component*"
Result: Atoms/Component/Default is snapshotted despite percy.skip: true.
Without --include: Atoms/Component/Default is correctly skipped.
The problem
When using the --include CLI flag with npx percy storybook, story-level parameters.percy.skip: true is silently ignored and snapshots are taken anyway. The skip flag works correctly when --include is not used.
Environment
@percy/cliversion: 1.31.4Details
In
shouldSkipStory(within the Storybook SDK), when any global filter (config.includeorconfig.exclude) is present, the function switches filter from options (the story) to config (the CLI config):Because
filteris nowconfig, theincludearray is built from the CLI flags. When the story name matches an--includepattern,include.some(matches)returnstrueandskipis set tofalse—options.skip(parameters.percy.skip: true) is never evaluated.This means that any story explicitly included via
--includecan never be skipped at the story level. The comment in the code says "if a global filter is present, disregard story filters", but this also discards theskipflag, which is not a filter — it is an opt-out mechanism independent of inclusion/exclusion logic.Expected: a story with
parameters.percy.skip: trueshould always be skipped, regardless of whether it was matched by a--includepattern.Actual: the story is snapshotted.
percy-storybook/src/snapshots.js
Lines 43 to 63 in 1200bcb
Suggested fix:
Debug logs
N/A — the behaviour is deterministic and the root cause is identified directly in the source.
Code to reproduce issue
Story file:
Percy invocation:
npx percy storybook ./dist/storybook --include "Atoms/Component*"Result:
Atoms/Component/Defaultis snapshotted despitepercy.skip: true.Without
--include: Atoms/Component/Defaultis correctly skipped.