如何在Storybook中为Angular组件添加宿主级Provider?
在Storybook中为Angular组件添加宿主级别Provider
问题背景
我们有两个Angular组件,ChildCmp通过@Optional() @Host()装饰器注入ParentCmp,这意味着它只会在自身的宿主元素层级查找该依赖:
@Component({ selector: "child-cmp", template: "<p>Hello</p>", }) class ChildCmp { constructor(@Optional() @Host() parentCmp: ParentCmp) {} } @Component({ selector: "parent-cmp", template: "<child-cmp></child-cmp>", }) class ParentCmp {}
在Angular单元测试中,我们可以通过TestBed.overrideComponent给ChildCmp添加宿主级Provider:
testBed.overrideComponent(ChildCmp, { add: { providers: [{ provide: ParentCmp, useValue: {} }], }, });
但在Storybook中,常规通过moduleMetadata添加的是模块级Provider,受限于@Host()的查找规则,这种方式无法被ChildCmp识别到:
const Template: Story<ChildCmp> = (args: ChildCmp) => ({ props: args, template: `<child-cmp></child-cmp>`, moduleMetadata: { providers: [ { provide: ParentCmp, useValue: {}, }, ], }, }); export const ChildCmp = Template.bind({});
解决方案
方法1:使用componentOverrides覆盖组件元数据
Storybook支持通过componentOverrides配置项,直接修改组件的元数据,效果和测试中的overrideComponent一致,能给组件添加宿主级Provider:
import { Meta, Story } from '@storybook/angular'; import { ChildCmp, ParentCmp } from './path-to-components'; const Template: Story<ChildCmp> = (args: ChildCmp) => ({ props: args, template: `<child-cmp></child-cmp>`, componentOverrides: { ChildCmp: { providers: [{ provide: ParentCmp, useValue: {} }] } } }); export const Default = Template.bind({}); Default.parameters = { component: ChildCmp };
方法2:创建临时宿主包装组件
如果你的Storybook版本不支持componentOverrides,可以手动创建一个临时的宿主组件,在该组件的providers中声明ParentCmp,再将ChildCmp嵌套在其中:
import { Component } from '@angular/core'; import { Meta, Story } from '@storybook/angular'; import { ChildCmp, ParentCmp } from './path-to-components'; // 临时宿主包装组件 @Component({ selector: 'host-wrapper', template: '<child-cmp></child-cmp>', providers: [{ provide: ParentCmp, useValue: {} }] }) class HostWrapperComponent {} const Template: Story<ChildCmp> = (args: ChildCmp) => ({ props: args, template: `<host-wrapper></host-wrapper>`, declarations: [HostWrapperComponent] }); export const Default = Template.bind({});
这两种方式都能让ChildCmp通过@Host()装饰器获取到对应的ParentCmp依赖,符合需求。
内容的提问来源于stack exchange,提问作者undefined
相关产品推荐
相关产品推荐

