Skip to content

Commit a3cdd39

Browse files
committed
feat: improved instructions and added new story
1 parent b3e1941 commit a3cdd39

8 files changed

Lines changed: 478 additions & 53 deletions

File tree

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# ComponentFramework-Mock
2+
## API Reference
3+
### Classes
4+
5+
#### `ComponentFrameworkMockGenerator<IInputs, IOutputs>`
6+
exported from `@shko.online/componentframework-mock`
7+
8+
**Properties:**
9+
10+
| Name | Type | Description |
11+
|------|------|-------------|
12+
| `db` | `MetadataDB` | - |
13+
| `context` | `ContextMock<IInputs>` | - |
14+
15+
**Methods:**
16+
17+
| Method | Returns | Description |
18+
|--------|---------|-------------|
19+
| `ExecuteInit()` | `void` | - |
20+
| `ExecuteUpdateView()` | `void` | - |
21+
22+
23+
---
24+
25+
<a name="componentframeworkmockgeneratorreact"></a>
26+
#### `ComponentFrameworkMockGeneratorReact<IInputs, IOutputs>`
27+
exported from `@shko.online/componentframework-mock`
28+
29+
**Properties:**
30+
31+
| Name | Type | Description |
32+
|------|------|-------------|
33+
| `db` | `MetadataDB` | - |
34+
| `context` | `ContextMock<IInputs>` | - |
35+
36+
**Methods:**
37+
38+
| Method | Returns | Description |
39+
|--------|---------|-------------|
40+
| `ExecuteInit()` | `void` | - |
41+
| `ExecuteUpdateView()` | `ReactElement` | - |
42+
43+
44+
---
45+
46+
<a name="componentframeworkmockorchestrator"></a>
47+
#### `ComponentFrameworkMockOrchestrator`
48+
exported from `@shko.online/componentframework-mock`
49+
50+
**Properties:**
51+
52+
| Name | Type | Description |
53+
|------|------|-------------|
54+
| `controls` | `OrchestratorInput<T>` | - |
55+
| `db` | `MetadataDB` | - |
56+
| `mockGenerators` | `OrchestratorGenerators<T>` | - |
57+
58+
**Methods:**
59+
60+
| Method | Returns | Description |
61+
|--------|---------|-------------|
62+
| `ExecuteInit()` | `void` | - |
63+
| `ExecuteUpdateView()` | `void` | - |
64+
65+
66+
---
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Standard Component Story Render Template
2+
If the `PCF` component is a Virtual component you must build a template to place in the `stories\{ComponentName}.render.ts` that uses `ComponentFrameworkMockGeneratorReact<IInputs, IOutputs>` to render the component as follows:
3+
4+
```ts
5+
// necessary imports
6+
7+
8+
export interface StoryArgs extends PCFStoryArgs {
9+
// story field definition based on component
10+
}
11+
12+
export const renderGenerator = () => {
13+
let container: HTMLDivElement | null;
14+
let mockGenerator: ComponentFrameworkMockGeneratorReact<IInputs, IOutputs>;
15+
16+
return function () {
17+
const [args, updateArgs] = useArgs<StoryArgs>();
18+
useEffect(
19+
() => () => {
20+
container = null;
21+
mockGenerator.control.destroy();
22+
},
23+
[]
24+
);
25+
if (!container) {
26+
container = document.createElement("div");
27+
container.className = "{ComponentName}";
28+
mockGenerator = new ComponentFrameworkMockGeneratorReact(
29+
ComponentName,
30+
{
31+
/*Parameter to PropertyMock Mapping*/
32+
},
33+
{
34+
/* output only types */
35+
}
36+
);
37+
38+
mockGenerator.context.mode.isVisible = args.isVisible;
39+
mockGenerator.context.mode.isControlDisabled = args.isDisabled;
40+
41+
mockGenerator.context._SetCanvasItems({
42+
/* Input or Bound Parameters mapped to story args */
43+
});
44+
45+
mockGenerator.ExecuteInit();
46+
}
47+
48+
if (mockGenerator) {
49+
mockGenerator.context.mode.isVisible = args.isVisible;
50+
mockGenerator.context.mode.isControlDisabled = args.isDisabled;
51+
// for each parameter of type input or bound we use the typed method to update the value from Storybook like follows `mockGenerator.context._parameters.{Parameter}._SetValue(args.{Parameter});`
52+
ReactDOM.render(mockGenerator.ExecuteUpdateView(), container);
53+
}
54+
55+
return container;
56+
};
57+
};
58+
59+
60+
```
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Standard Component Story Render Template
2+
If the `PCF` component is a standard component you must build a template to place in the `stories\{ComponentName}.render.ts` that uses `ComponentFrameworkMockGenerator<IInputs, IOutputs>` to render the component as follows:
3+
4+
```ts
5+
// necessary imports
6+
7+
8+
export interface StoryArgs extends PCFStoryArgs {
9+
// story field definition based on component
10+
}
11+
12+
export const renderGenerator = () => {
13+
let container: HTMLDivElement | null;
14+
let mockGenerator: ComponentFrameworkMockGenerator<IInputs, IOutputs>;
15+
16+
return function () {
17+
const [args, updateArgs] = useArgs<StoryArgs>();
18+
useEffect(
19+
() => () => {
20+
container = null;
21+
mockGenerator.control.destroy();
22+
},
23+
[]
24+
);
25+
if (!container) {
26+
container = document.createElement("div");
27+
container.className = "{ComponentName}";
28+
mockGenerator = new ComponentFrameworkMockGenerator(
29+
ComponentName,
30+
{
31+
/*Parameter to PropertyMock Mapping*/
32+
},
33+
container,
34+
{
35+
/* output only types */
36+
}
37+
);
38+
39+
mockGenerator.context.mode.isVisible = args.isVisible;
40+
mockGenerator.context.mode.isControlDisabled = args.isDisabled;
41+
42+
mockGenerator.context._SetCanvasItems({
43+
/* Input or Bound Parameters mapped to story args */
44+
});
45+
46+
mockGenerator.ExecuteInit();
47+
}
48+
49+
if (mockGenerator) {
50+
mockGenerator.context.mode.isVisible = args.isVisible;
51+
mockGenerator.context.mode.isControlDisabled = args.isDisabled;
52+
// for each parameter of type input or bound we use the typed method to update the value from Storybook like follows `mockGenerator.context._parameters.{Parameter}._SetValue(args.{Parameter});`
53+
mockGenerator.ExecuteUpdateView();
54+
}
55+
56+
return container;
57+
};
58+
};
59+
60+
61+
```

.github/instructions/ComponentFramework-Mock.instructions.md

Lines changed: 6 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ This library provides classes that simplify executing `PCF` components in a test
1212

1313
- [Usage](#usage)
1414
- [Story Setup](#story-setup)
15-
- [API Reference](#api-reference)
16-
- [Classes](#classes)
15+
- [API Reference](@shko.online/ComponentFramework-Mock.API#api-reference)
16+
- [Classes](@shko.online/ComponentFramework-Mock.API#classes)
1717
- [ComponentFrameworkMockGenerator](#componentframeworkmockgenerator)
1818
- [ComponentFrameworkMockGeneratorReact](#componentframeworkmockgeneratorreact)
1919
- [ComponentFrameworkMockOrchestrator](#componentframeworkmockorchestrator)
@@ -27,7 +27,7 @@ There are three main classes in this library that can be used to create a mock c
2727
2. `ComponentFrameworkMockGeneratorReact`: This class generates a mock context for a virtual `PCF` component that uses `React` based on the provided configuration.
2828
3. `ComponentFrameworkMockOrchestrator`: This class orchestrates the generation of mock contexts for multiple components, allowing you to manage and execute tests across different components in a unified manner.
2929

30-
To use these classes, you can follow the examples provided in the [API Reference](#api-reference) section below. Each class has its own set of methods and properties that allow you to customize the mock context according to your testing needs.
30+
To use these classes, you can follow the examples provided in the [API Reference](@shko.online/ComponentFramework-Mock.API#api-reference) section below. Each class has its own set of methods and properties that allow you to customize the mock context according to your testing needs.
3131

3232
## Story Setup
3333

@@ -43,9 +43,9 @@ make sure to run `npm install` after modifying the workspaces to ensure the new
4343

4444
make sure to run `npm run refreshTypes` after modifying the workspaces to ensure the new component types are properly refreshed.
4545

46-
Always read the `ControlManifest.Input.xml` file of the component to understand the expected inputs, outputs, and resources as this will help you set up the mock context correctly. From this file you can determine the `IInputs` and `IOutputs` types, as well as any `resx` or `css` that need to be loaded for the component.
46+
Always read the `ControlManifest.Input.xml` file of the component to understand the expected inputs, outputs, and resources as this will help you set up the mock context correctly. From this file you can determine the `IInputs` and `IOutputs` types, as well as any `resx` or `css` that need to be loaded for the component. From `ControlManifest.Input.xml` you can also determine if the component uses `React` (defined by `control-type="virtual"`) or not which will help you decide which mock generator class to use. You should always tell the user which mock generator class you decided to use based on the `control-type` defined in the `ControlManifest.Input.xml` file.
4747

48-
check if the Storybook component brige file is set up. If not, create a new file in the `Storybook/Stories/Components` folder named `{ComponentName}.ts` and add the following code:
48+
check if the Storybook component bridge file is set up. If not, create a new file in the `Storybook/Stories/Components` folder named `{ComponentName}.ts` and add the following code:
4949

5050
if a `resx` file is used by the component, make sure to load it using the `getFromResource` function exported from the component bridge file as shown below:
5151

@@ -64,51 +64,4 @@ export type { IInputs, IOutputs } from "Relative Path to ManifestTypes";
6464

6565
```
6666

67-
<a name="api-reference"></a>
68-
## API Reference
69-
### Classes
70-
71-
72-
73-
<a name="componentframeworkmock"></a>
74-
#### `ComponentFrameworkMock<IInputs, IOutputs>`
75-
exported from `@shko.online/componentframework-mock/ComponentFrameworkMock`
76-
77-
**Properties:**
78-
79-
| Name | Type | Description |
80-
|------|------|-------------|
81-
| `db` | `MetadataDB` | - |
82-
| `context` | `ContextMock<IInputs>` | - |
83-
84-
**Methods:**
85-
86-
| Method | Returns | Description |
87-
|--------|---------|-------------|
88-
| `ExecuteInit()` | `void` | - |
89-
| `ExecuteUpdateView()` | `void` | - |
90-
91-
92-
---
93-
94-
<a name="componentframeworkmockorchestrator"></a>
95-
#### `ComponentFrameworkMockOrchestrator`
96-
exported from `@shko.online/componentframework-mock/ComponentFrameworkMockOrchestrator`
97-
98-
**Properties:**
99-
100-
| Name | Type | Description |
101-
|------|------|-------------|
102-
| `controls` | `OrchestratorInput<T>` | - |
103-
| `db` | `MetadataDB` | - |
104-
| `mockGenerators` | `OrchestratorGenerators<T>` | - |
105-
106-
**Methods:**
107-
108-
| Method | Returns | Description |
109-
|--------|---------|-------------|
110-
| `ExecuteInit()` | `void` | - |
111-
| `ExecuteUpdateView()` | `void` | - |
112-
113-
114-
---
67+
if the component is a standard component use the `ComponentFrameworkMockGenerator` class to create a render function for the story as shown in the [Standard Component Story Render Template](@shko.online/StandardComponentStoryRenderTemplate) instructions file. If the component is a virtual `React` component use the `ComponentFrameworkMockGeneratorReact` class to create a render function for the story as shown in the [React Component Story Render Template](@shko.online/ReactComponentStoryRenderTemplate) instructions file.

.vscode/tasks.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"label": "Run Storybook",
6+
"type": "shell",
7+
"command": "npm",
8+
"args": [
9+
"run",
10+
"storybook"
11+
],
12+
"isBackground": true
13+
}
14+
]
15+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export type {
2+
IInputs,
3+
IOutputs,
4+
} from "../../../Facepile/Facepile/generated/ManifestTypes";
5+
import innerResource from "raw-loader!!../../../Facepile/Facepile/strings/Facepile.1033.resx";
6+
export * as resource from "raw-loader!!../../../Facepile/Facepile/strings/Facepile.1033.resx";
7+
import { generateGetFromResource } from "../getFromResourceGenerator";
8+
export { Facepile } from "../../../Facepile/Facepile";
9+
export { ItemColumns, OutputEvents } from "../../../Facepile/Facepile/ManifestConstants";
10+
export const getFromResource = generateGetFromResource(innerResource);

0 commit comments

Comments
 (0)