Storybook中如何配置Jest快照测试时忽略特定样式属性?

晏鸣 Dev 阅读 72

我在给React组件写Storybook快照测试时遇到问题,快照里总是包含组件上不需要的样式属性,比如data-testid。我尝试在Jest配置里加了snapshotSerializers,但还是报错说快照不匹配,应该怎么排除这些属性呢?

具体场景是这样的:我用Storybook+Jest做快照测试,组件有data-testid="button"这样的测试辅助属性。执行测试时快照里会包含这个属性,但我想只保留组件的核心结构。之前试过修改jest.config.js


module.exports = {
  snapshotSerializers: ['@testing-library/react-native/serializer'],
  // 其他配置...
};

但运行npm test时仍然得到这样的错误:


- Received value does not match stored snapshot.
  
  - Diff:
    @@ -10,10 +10,9 @@
        "props": {
          "children": "Click me",
          "className": "primary-btn",
    -     "data-testid": "button",
          "onClick": [Function]
        },
    ...

有什么办法能全局配置快照测试忽略特定属性吗?或者需要在Storybook的预处理器里做处理?

我来解答 赞 13 收藏
二维码
手机扫码查看
2 条解答
Tr° 闪闪
这个问题其实挺常见的,snapshotSerializers的方向是对的,但需要自定义一个serializer来过滤属性。

在jest.config.js里这样配置:

module.exports = {
snapshotSerializers: [
{
print: (element, serializer) => {
if (!element || typeof element !== 'object') {
return serializer.print(element, serializer);
}

const clone = { ...element };
if (clone.props && typeof clone.props === 'object') {
const { 'data-testid': _ignored, ...restProps } = clone.props;
clone.props = restProps;
}

return serializer.print(clone, serializer);
},
test: (element) => {
return element && typeof element === 'object' && element.props !== undefined;
},
},
],
};


这样配置完再跑测试,data-testid就不会出现在快照里了。

如果你想同时排除多个属性,可以这样改:

const propsToRemove = ['data-testid', 'data-cy', 'testId'];

module.exports = {
snapshotSerializers: [
{
print: (element, serializer) => {
if (!element || typeof element !== 'object') {
return serializer.print(element, serializer);
}

const clone = { ...element };
if (clone.props && typeof clone.props === 'object') {
const filteredProps = {};
Object.keys(clone.props).forEach(key => {
if (!propsToRemove.includes(key)) {
filteredProps[key] = clone.props[key];
}
});
clone.props = filteredProps;
}

return serializer.print(clone, serializer);
},
test: (element) => {
return element && typeof element === 'object' && element.props !== undefined;
},
},
],
};


另外提醒一下,官方文档里说Storybook 7+推荐用test runner配合playwright做交互测试,快照测试这种方案在大型项目里维护成本其实挺高的,能不用尽量少用。
点赞
2026-03-19 12:04
远香(打工版)
你这个需求其实挺常见的,data-testid 这种测试属性确实不该进快照。问题出在你用的 serializer 不对路——@testing-library/react-native/serializer 是给 React Native 用的,你在 Web 环境下用它基本没效果。

标准写法是用 @storybook/testing-react 提供的预处理器机制,在快照序列化前把不需要的属性过滤掉。你可以通过自定义一个 snapshot serializer 来实现全局过滤。

在项目根目录新建一个文件,比如 jest-serializer-remove-test-ids.js

const reactElement = Symbol.for('react.element');

module.exports = {
test(val) {
return val && val.$$typeof === reactElement;
},
serialize(element, config, indentation, depth, refs, printer) {
const filteredProps = { ...element.props };
delete filteredProps['data-testid'];
// 如果还有其他想忽略的也可以删,比如 data-cy、aria-label 测试用的等
// delete filteredProps['data-cy'];

const filteredElement = {
...element,
props: filteredProps,
};

return printer(filteredElement, config, indentation, depth, refs);
},
};


然后在 jest.config.js 里注册这个 serializer:

module.exports = {
setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect'],
snapshotSerializers: ['/jest-serializer-remove-test-ids.js'],
};


注意路径要写对,可以用 path.resolve 引入。

这样所有快照里的 data-testid 都会被自动移除,不会再出现 diff 报错。而且这是全局生效的,不用每个 story 单独处理。

另外提醒一点,别指望 Storybook 的 render 预处理能解决这个问题,因为快照是 Jest 拿到的 VDOM 结构,必须在序列化阶段动手脚才有效。这套方案是目前社区的标准做法,文档也明确推荐过类似模式。
点赞 6
2026-02-12 22:03