故事书:在组件级别注入模拟的 provider/service
Storybook: Inject a mocked provider/service at component level
我有一个 Angular 组件,该组件具有组件级提供程序。
@Component({
selector: 'storybook-di-component',
templateUrl: './di.component.html',
providers: [{ provide: TEST_TOKEN, useValue: 123 }],
})
export class DiComponent {
@Input()
title: string;
constructor(
protected injector: Injector,
protected elRef: ElementRef,
@Inject(TEST_TOKEN) protected testToken: number
) {}
在这种情况下,如何让 Storybook 注入不同的提供程序以便我可以提供 alternate/mock 服务?例如,在上面的 DiComponent 中,如果我想注入 { provide: TEST_TOKEN, useValue: 456 }
怎么办?
真实世界的用例是我正在使用 ngrx/component-store 并且需要为组件提供一个虚拟的、预填充的商店。
(附加信息:)
在模块级别注入它(如下所示)不起作用,因为组件仍在运行并创建它自己的提供程序实例:
moduleMetadata: {
providers: [
{ provide: StateStore, useValue: stateStore }
],
imports: [...],
},
我最终使用低技术方法解决了这个问题。
- Subclass
.stories.ts
文件中的组件
- 在子 class 中,声明构造函数以注入除需要模拟的服务之外的所有内容。
- 使用注入服务 + 模拟服务调用
super(...)
。
鉴于我的实际需要是注入 ngrx/component-store
的模拟,我的 stories.ts
现在有如下内容:
const stateStore = new RecordSuggestionsPageStore(mockSuggestionsService);
stateStore.setState(() => ({
selectableRecords: [
{ name: "John Legend", recordType: "employee" },
{ name: "Allan Davies", recordType: "employee" },
]
}));
@Component({
selector: "myapp-suggested-records-page",
templateUrl: "./suggested-records-page.component.html",
styleUrls: ["./suggested-records-page.component.scss"]
})
class SuggestedRecordsPageComponentStubbed extends SuggestedRecordsPageComponent {
constructor(router: Router) {
super(stateStore, router);
}
}
TypeProvider 适合我。对于您的示例,它类似于以下内容,其中 setState 的参数需要与被模拟的方法相匹配:
class MockRecordSuggestionsPageStore implements Partial<RecordSuggestionsPageStore> {
setState() {
return [
{ name: "John Legend", recordType: "employee" },
{ name: "Allan Davies", recordType: "employee" },
]
}
}
对于 SuggestedRecordsPageComponent 故事中的提供商
moduleMetadata: {
declarations: [...],
imports: [...],
providers: [
{ provide: StateStore, useClass: MockRecordSuggestionsPageStore }
],
},
我有一个 Angular 组件,该组件具有组件级提供程序。
@Component({
selector: 'storybook-di-component',
templateUrl: './di.component.html',
providers: [{ provide: TEST_TOKEN, useValue: 123 }],
})
export class DiComponent {
@Input()
title: string;
constructor(
protected injector: Injector,
protected elRef: ElementRef,
@Inject(TEST_TOKEN) protected testToken: number
) {}
在这种情况下,如何让 Storybook 注入不同的提供程序以便我可以提供 alternate/mock 服务?例如,在上面的 DiComponent 中,如果我想注入 { provide: TEST_TOKEN, useValue: 456 }
怎么办?
真实世界的用例是我正在使用 ngrx/component-store 并且需要为组件提供一个虚拟的、预填充的商店。
(附加信息:) 在模块级别注入它(如下所示)不起作用,因为组件仍在运行并创建它自己的提供程序实例:
moduleMetadata: {
providers: [
{ provide: StateStore, useValue: stateStore }
],
imports: [...],
},
我最终使用低技术方法解决了这个问题。
- Subclass
.stories.ts
文件中的组件 - 在子 class 中,声明构造函数以注入除需要模拟的服务之外的所有内容。
- 使用注入服务 + 模拟服务调用
super(...)
。
鉴于我的实际需要是注入 ngrx/component-store
的模拟,我的 stories.ts
现在有如下内容:
const stateStore = new RecordSuggestionsPageStore(mockSuggestionsService);
stateStore.setState(() => ({
selectableRecords: [
{ name: "John Legend", recordType: "employee" },
{ name: "Allan Davies", recordType: "employee" },
]
}));
@Component({
selector: "myapp-suggested-records-page",
templateUrl: "./suggested-records-page.component.html",
styleUrls: ["./suggested-records-page.component.scss"]
})
class SuggestedRecordsPageComponentStubbed extends SuggestedRecordsPageComponent {
constructor(router: Router) {
super(stateStore, router);
}
}
TypeProvider 适合我。对于您的示例,它类似于以下内容,其中 setState 的参数需要与被模拟的方法相匹配:
class MockRecordSuggestionsPageStore implements Partial<RecordSuggestionsPageStore> {
setState() {
return [
{ name: "John Legend", recordType: "employee" },
{ name: "Allan Davies", recordType: "employee" },
]
}
}
对于 SuggestedRecordsPageComponent 故事中的提供商
moduleMetadata: {
declarations: [...],
imports: [...],
providers: [
{ provide: StateStore, useClass: MockRecordSuggestionsPageStore }
],
},