@microsoft/fast-test-harness 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -19
- package/dist/dts/build/generate-templates.d.ts +35 -0
- package/dist/dts/build/generate-templates.d.ts.map +1 -1
- package/dist/dts/build/generate-webui-templates.d.ts +14 -1
- package/dist/dts/build/generate-webui-templates.d.ts.map +1 -1
- package/dist/dts/fixtures/csr-fixture.d.ts +28 -0
- package/dist/dts/fixtures/csr-fixture.d.ts.map +1 -1
- package/dist/dts/fixtures/ssr-fixture.d.ts +19 -0
- package/dist/dts/fixtures/ssr-fixture.d.ts.map +1 -1
- package/dist/dts/ssr/render.d.ts +11 -16
- package/dist/dts/ssr/render.d.ts.map +1 -1
- package/dist/esm/build/generate-templates.js +62 -2
- package/dist/esm/build/generate-webui-templates.js +9 -26
- package/dist/esm/fixtures/ssr-fixture.js +19 -1
- package/dist/esm/ssr/render.js +48 -104
- package/package.json +26 -15
- package/dist/dts/build/dom-shim.test.d.ts +0 -2
- package/dist/dts/build/dom-shim.test.d.ts.map +0 -1
- package/dist/dts/build/generate-stylesheets.test.d.ts +0 -2
- package/dist/dts/build/generate-stylesheets.test.d.ts.map +0 -1
- package/dist/dts/build/generate-templates.test.d.ts +0 -2
- package/dist/dts/build/generate-templates.test.d.ts.map +0 -1
- package/dist/dts/build/generate-webui-templates.test.d.ts +0 -2
- package/dist/dts/build/generate-webui-templates.test.d.ts.map +0 -1
- package/dist/dts/fixtures/csr-fixture.pw.spec.d.ts +0 -2
- package/dist/dts/fixtures/csr-fixture.pw.spec.d.ts.map +0 -1
- package/dist/dts/fixtures/ssr-fixture.pw.spec.d.ts +0 -2
- package/dist/dts/fixtures/ssr-fixture.pw.spec.d.ts.map +0 -1
- package/dist/dts/ssr/render.test.d.ts +0 -2
- package/dist/dts/ssr/render.test.d.ts.map +0 -1
- package/dist/esm/build/dom-shim.test.js +0 -202
- package/dist/esm/build/generate-stylesheets.test.js +0 -74
- package/dist/esm/build/generate-templates.test.js +0 -231
- package/dist/esm/build/generate-webui-templates.test.js +0 -179
- package/dist/esm/fixtures/csr-fixture.pw.spec.js +0 -137
- package/dist/esm/fixtures/ssr-fixture.pw.spec.js +0 -189
- package/dist/esm/ssr/render.test.js +0 -236
package/README.md
CHANGED
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
The `fast-test-harness` package is a Playwright testing harness for FAST Element web components with CSR and SSR support.
|
|
6
6
|
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Node.js 22.18 or later
|
|
10
|
+
- Playwright 1.56 or later
|
|
11
|
+
|
|
7
12
|
## Installation
|
|
8
13
|
|
|
9
14
|
To install `fast-test-harness` using `npm`:
|
|
@@ -12,6 +17,21 @@ To install `fast-test-harness` using `npm`:
|
|
|
12
17
|
npm install --save-dev @microsoft/fast-test-harness
|
|
13
18
|
```
|
|
14
19
|
|
|
20
|
+
## Test directory setup
|
|
21
|
+
|
|
22
|
+
The harness serves a Vite dev server from a `test/` directory in your project. CSR and SSR modes use different entry points from the same directory.
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
test/
|
|
26
|
+
├── index.html # CSR: loads main.ts
|
|
27
|
+
├── ssr.html # SSR: template with comment placeholders
|
|
28
|
+
├── vite.config.ts # Vite config (shared by both modes)
|
|
29
|
+
└── src/
|
|
30
|
+
├── main.ts # CSR: registers components, applies theme
|
|
31
|
+
├── entry-client.ts # SSR: registers components for hydration
|
|
32
|
+
└── entry-server.ts # SSR: exports render() for fixture generation
|
|
33
|
+
```
|
|
34
|
+
|
|
15
35
|
## Writing tests
|
|
16
36
|
|
|
17
37
|
Import `test` and `expect` from the harness. Configure the component tag name with `test.use()`, then call `fastPage.setTemplate()` in each test to render it.
|
|
@@ -67,21 +87,6 @@ await expect(element).toHaveCustomState("checked");
|
|
|
67
87
|
| `waitFor` | `string[]` | `[]` | Additional elements to wait for before testing |
|
|
68
88
|
| `ssr` | `boolean` | `false` | Use SSR mode (or set `PLAYWRIGHT_TEST_SSR=true`) |
|
|
69
89
|
|
|
70
|
-
## Test directory setup
|
|
71
|
-
|
|
72
|
-
The harness serves a Vite dev server from a `test/` directory in your project. CSR and SSR modes use different entry points from the same directory.
|
|
73
|
-
|
|
74
|
-
```
|
|
75
|
-
test/
|
|
76
|
-
├── index.html # CSR: loads main.ts
|
|
77
|
-
├── ssr.html # SSR: template with comment placeholders
|
|
78
|
-
├── vite.config.ts # Vite config (shared by both modes)
|
|
79
|
-
└── src/
|
|
80
|
-
├── main.ts # CSR: registers components, applies theme
|
|
81
|
-
├── entry-client.ts # SSR: registers components for hydration
|
|
82
|
-
└── entry-server.ts # SSR: exports render() for fixture generation
|
|
83
|
-
```
|
|
84
|
-
|
|
85
90
|
### CSR files
|
|
86
91
|
|
|
87
92
|
**`index.html`** loads a script that registers your components:
|
|
@@ -248,7 +253,7 @@ CLI flags take precedence over environment variables.
|
|
|
248
253
|
|
|
249
254
|
| Option | Type | Description |
|
|
250
255
|
|--------|------|-------------|
|
|
251
|
-
| `tagPrefix` | `string` | Tag name prefix for custom elements (e.g., `"fluent"`, `"
|
|
256
|
+
| `tagPrefix` | `string` | Tag name prefix for custom elements (e.g., `"fluent"`, `"contoso"`) |
|
|
252
257
|
| `packageName` | `string?` | Monolithic package name — scans subdirectories for component artifacts. Mutually exclusive with `components`. |
|
|
253
258
|
| `components` | `ComponentRegistration[]?` | Explicit list of per-component packages. Mutually exclusive with `packageName`. |
|
|
254
259
|
| `distDir` | `string?` | Artifact directory relative to the package root (default: `"dist/esm"`). Only used with `packageName`. |
|
|
@@ -258,10 +263,11 @@ CLI flags take precedence over environment variables.
|
|
|
258
263
|
|
|
259
264
|
| Specifier | Contents |
|
|
260
265
|
|-----------|----------|
|
|
261
|
-
| `@microsoft/fast-test-harness` | `test`, `expect`, `CSRFixture`, `SSRFixture`, `
|
|
266
|
+
| `@microsoft/fast-test-harness` | `test`, `expect`, `CSRFixture`, `SSRFixture`, `toHaveCustomState`, `installDomShim`, `createSSRRenderer` |
|
|
267
|
+
| `@microsoft/fast-test-harness/build/*.js` | `installDomShim`, `generateStylesheets`, `generateFTemplates`, `generateWebuiTemplates`, `definitionAsyncResolver`, `shadowOptionsToAttributes`, `ShadowOptionsResolver` |
|
|
268
|
+
| `@microsoft/fast-test-harness/fixtures/*.js` | `CSRFixture`, `SSRFixture`, `toHaveCustomState`, extended `test` and `expect` |
|
|
269
|
+
| `@microsoft/fast-test-harness/ssr/render.js` | `createSSRRenderer`, `renderTemplate`, `buildEntryHtml`, `buildState` |
|
|
262
270
|
| `@microsoft/fast-test-harness/server.mjs` | `startServer` |
|
|
263
|
-
| `@microsoft/fast-test-harness/ssr/render.js` | `createSSRRenderer`, `ComponentRegistration`, `RenderResult`, `SSRRendererOptions` |
|
|
264
|
-
| `@microsoft/fast-test-harness/build/*.js` | `installDomShim`, `generateStylesheets`, `generateFTemplates`, `generateWebuiTemplates` |
|
|
265
271
|
| `@microsoft/fast-test-harness/playwright.config.mjs` | Shared Playwright configuration |
|
|
266
272
|
| `@microsoft/fast-test-harness/vite.config.mjs` | Shared Vite configuration |
|
|
267
273
|
| `@microsoft/fast-test-harness/public/*` | Static assets (base CSS) |
|
|
@@ -45,7 +45,37 @@ export interface GenerateFTemplatesOptions {
|
|
|
45
45
|
* Optional formatter function applied to generated HTML before writing.
|
|
46
46
|
*/
|
|
47
47
|
format?: (html: string, filePath: string) => string | Promise<string>;
|
|
48
|
+
/**
|
|
49
|
+
* Resolves shadow DOM options for a given template module path.
|
|
50
|
+
* Returns a `shadowOptions` object (e.g. `{ delegatesFocus: true }`) or
|
|
51
|
+
* `undefined` if the component has no special shadow options.
|
|
52
|
+
*
|
|
53
|
+
* Defaults to {@link definitionAsyncResolver}, which loads a companion
|
|
54
|
+
* `*.definition-async.js` module next to each template. Set to `null`
|
|
55
|
+
* to disable shadow options resolution.
|
|
56
|
+
*
|
|
57
|
+
* @default definitionAsyncResolver
|
|
58
|
+
*/
|
|
59
|
+
resolveShadowOptions?: ShadowOptionsResolver | null;
|
|
48
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* A function that resolves shadow DOM options for a template module.
|
|
63
|
+
* Receives the absolute path to the compiled `*.template.js` file and
|
|
64
|
+
* returns shadow options or `undefined`.
|
|
65
|
+
*/
|
|
66
|
+
export type ShadowOptionsResolver = (templateJsPath: string) => Record<string, unknown> | undefined | Promise<Record<string, unknown> | undefined>;
|
|
67
|
+
/**
|
|
68
|
+
* Convention-based resolver that loads a companion `*.definition-async.js`
|
|
69
|
+
* module next to the template module and returns its `shadowOptions`.
|
|
70
|
+
*
|
|
71
|
+
* For a template at `dist/textarea/textarea.template.js`, this looks for
|
|
72
|
+
* `dist/textarea/textarea.definition-async.js`.
|
|
73
|
+
*
|
|
74
|
+
* This is the default resolver used by {@link generateFTemplates} and
|
|
75
|
+
* {@link generateWebuiTemplates} when `resolveShadowOptions` is not
|
|
76
|
+
* specified.
|
|
77
|
+
*/
|
|
78
|
+
export declare function definitionAsyncResolver(templateJsPath: string): Promise<Record<string, unknown> | undefined>;
|
|
49
79
|
export interface ViewTemplate {
|
|
50
80
|
html: string | HTMLTemplateElement;
|
|
51
81
|
factories: Record<string, Factory>;
|
|
@@ -64,6 +94,11 @@ interface Factory {
|
|
|
64
94
|
* f-template HTML string.
|
|
65
95
|
*/
|
|
66
96
|
export declare function convertTemplate(viewTemplate: ViewTemplate, componentName: string): string | null;
|
|
97
|
+
/**
|
|
98
|
+
* Convert a `shadowOptions` object (e.g. `{ delegatesFocus: true }`) into
|
|
99
|
+
* DSD template attribute entries (e.g. `{ shadowrootdelegatesfocus: "" }`).
|
|
100
|
+
*/
|
|
101
|
+
export declare function shadowOptionsToAttributes(shadowOptions: Record<string, unknown> | undefined): Record<string, string>;
|
|
67
102
|
export declare function generateFTemplates(options?: GenerateFTemplatesOptions): Promise<void>;
|
|
68
103
|
export {};
|
|
69
104
|
//# sourceMappingURL=generate-templates.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-templates.d.ts","sourceRoot":"","sources":["../../../src/build/generate-templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AA8BH,MAAM,WAAW,yBAAyB;IACtC;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"generate-templates.d.ts","sourceRoot":"","sources":["../../../src/build/generate-templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AA8BH,MAAM,WAAW,yBAAyB;IACtC;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEtE;;;;;;;;;;OAUG;IACH,oBAAoB,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAC;CACvD;AAED;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAChC,cAAc,EAAE,MAAM,KACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,CAAC;AAExF;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CACzC,cAAc,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,CAY9C;AAED,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE,MAAM,GAAG,mBAAmB,CAAC;IACnC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,UAAU,OAAO;IACb,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,WAAW,CAAC,EAAE;QACV,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC;KACrC,CAAC;CACL;AAmFD;;;GAGG;AACH,wBAAgB,eAAe,CAC3B,YAAY,EAAE,YAAY,EAC1B,aAAa,EAAE,MAAM,GACtB,MAAM,GAAG,IAAI,CA4Hf;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACrC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GACnD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmBxB;AAED,wBAAsB,kBAAkB,CACpC,OAAO,GAAE,yBAA8B,GACxC,OAAO,CAAC,IAAI,CAAC,CAgFf"}
|
|
@@ -14,9 +14,10 @@
|
|
|
14
14
|
* ```ts
|
|
15
15
|
* import { generateWebuiTemplates } from "@microsoft/fast-test-harness/build/generate-webui-templates.js";
|
|
16
16
|
*
|
|
17
|
-
* await generateWebuiTemplates({ cwd: process.cwd(), tagPrefix: "
|
|
17
|
+
* await generateWebuiTemplates({ cwd: process.cwd(), tagPrefix: "contoso" });
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
|
+
import { type ShadowOptionsResolver } from "./generate-templates.js";
|
|
20
21
|
export interface GenerateWebuiTemplatesOptions {
|
|
21
22
|
/**
|
|
22
23
|
* Root directory of the package. Defaults to `process.cwd()`.
|
|
@@ -49,6 +50,18 @@ export interface GenerateWebuiTemplatesOptions {
|
|
|
49
50
|
* Optional formatter function applied to generated HTML before writing.
|
|
50
51
|
*/
|
|
51
52
|
format?: (html: string, filePath: string) => string | Promise<string>;
|
|
53
|
+
/**
|
|
54
|
+
* Resolves shadow DOM options for a given template module path.
|
|
55
|
+
* Returns a `shadowOptions` object (e.g. `{ delegatesFocus: true }`) or
|
|
56
|
+
* `undefined` if the component has no special shadow options.
|
|
57
|
+
*
|
|
58
|
+
* Defaults to {@link definitionAsyncResolver}, which loads a companion
|
|
59
|
+
* `*.definition-async.js` module next to each template. Set to `null`
|
|
60
|
+
* to disable shadow options resolution.
|
|
61
|
+
*
|
|
62
|
+
* @default definitionAsyncResolver
|
|
63
|
+
*/
|
|
64
|
+
resolveShadowOptions?: ShadowOptionsResolver | null;
|
|
52
65
|
}
|
|
53
66
|
export declare function generateWebuiTemplates(options?: GenerateWebuiTemplatesOptions): Promise<void>;
|
|
54
67
|
//# sourceMappingURL=generate-webui-templates.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-webui-templates.d.ts","sourceRoot":"","sources":["../../../src/build/generate-webui-templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;
|
|
1
|
+
{"version":3,"file":"generate-webui-templates.d.ts","sourceRoot":"","sources":["../../../src/build/generate-webui-templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,OAAO,EAGH,KAAK,qBAAqB,EAG7B,MAAM,yBAAyB,CAAC;AAQjC,MAAM,WAAW,6BAA6B;IAC1C;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEtE;;;;;;;;;;OAUG;IACH,oBAAoB,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAC;CACvD;AA4CD,wBAAsB,sBAAsB,CACxC,OAAO,GAAE,6BAAkC,GAC5C,OAAO,CAAC,IAAI,CAAC,CA6Ef"}
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import type { Locator, Page } from "@playwright/test";
|
|
2
2
|
export type ThemeTokens = Record<string, string | number | boolean>;
|
|
3
|
+
/**
|
|
4
|
+
* The initial attributes for the fixture's template, where boolean attributes are
|
|
5
|
+
* represented as `true` and omitted when `false`. This allows for a more intuitive
|
|
6
|
+
* configuration of boolean attributes in the template options.
|
|
7
|
+
*/
|
|
3
8
|
export type InitialTemplateAttributes = Record<string, string | true>;
|
|
9
|
+
/**
|
|
10
|
+
* The attributes for the fixture's template, where boolean attributes can be represented as `true`
|
|
11
|
+
* or `false`. When `true`, the attribute will be included without a value (e.g., `disabled`), and
|
|
12
|
+
* when `false`, the attribute will be omitted entirely. This type is used for updating the
|
|
13
|
+
* template, allowing for both adding and removing boolean attributes.
|
|
14
|
+
*/
|
|
4
15
|
export type TemplateAttributes = Record<string, string | boolean>;
|
|
5
16
|
/**
|
|
6
17
|
* The options for configuring the fixture's template.
|
|
@@ -9,6 +20,10 @@ export type InitialTemplateOptions = {
|
|
|
9
20
|
attributes?: InitialTemplateAttributes;
|
|
10
21
|
innerHTML?: string;
|
|
11
22
|
};
|
|
23
|
+
/**
|
|
24
|
+
* The options for updating the fixture's template, where `attributes` can include boolean values to
|
|
25
|
+
* add or remove attributes from the element.
|
|
26
|
+
*/
|
|
12
27
|
export type FixtureOptions = Omit<InitialTemplateOptions, "attributes"> & {
|
|
13
28
|
attributes?: TemplateAttributes;
|
|
14
29
|
};
|
|
@@ -36,6 +51,19 @@ export declare class CSRFixture {
|
|
|
36
51
|
protected readonly innerHTML: string;
|
|
37
52
|
/**
|
|
38
53
|
* Additional custom elements to wait for before running the test.
|
|
54
|
+
*
|
|
55
|
+
* @remarks
|
|
56
|
+
* This is useful for fixtures that depend on multiple custom elements being defined
|
|
57
|
+
* and stable before the test can run. By specifying additional tag names here, the
|
|
58
|
+
* fixture will wait for these elements to be defined before proceeding. Ensure that
|
|
59
|
+
* any elements specified here are included on the page and properly defined to
|
|
60
|
+
* prevent test timeouts.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* test.use({
|
|
64
|
+
* tagName: "fast-dropdown",
|
|
65
|
+
* waitFor: ["fast-listbox", "fast-option"],
|
|
66
|
+
* });
|
|
39
67
|
*/
|
|
40
68
|
protected readonly waitFor: string[];
|
|
41
69
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csr-fixture.d.ts","sourceRoot":"","sources":["../../../src/fixtures/csr-fixture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;AAEpE,MAAM,MAAM,yBAAyB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;AAEtE,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;AAElE;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACjC,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,sBAAsB,EAAE,YAAY,CAAC,GAAG;IACtE,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACnC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,sBAAsB,GAAG,MAAM,CAAC;AAEhE;;GAEG;AACH,qBAAa,UAAU;
|
|
1
|
+
{"version":3,"file":"csr-fixture.d.ts","sourceRoot":"","sources":["../../../src/fixtures/csr-fixture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;AAEpE;;;;GAIG;AACH,MAAM,MAAM,yBAAyB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;AAEtE;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;AAElE;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACjC,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,sBAAsB,EAAE,YAAY,CAAC,GAAG;IACtE,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACnC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,sBAAsB,GAAG,MAAM,CAAC;AAEhE;;GAEG;AACH,qBAAa,UAAU;aA2CC,IAAI,EAAE,IAAI;IA1C9B;;OAEG;IACH,SAAgB,OAAO,EAAE,OAAO,CAAC;IAEjC;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEnC;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAErC;;;;;;;;;;;;;;;OAeG;IACH,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAErC;;;;;;;OAOG;IACH,YACoB,IAAI,EAAE,IAAI,EAC1B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,MAAM,EAAO,EAMzB;IAED;;;;;OAKG;IACG,WAAW,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5E;IAED;;;;OAIG;IACG,IAAI,CAAC,GAAG,GAAE,MAAY,iBAE3B;IAED;;;;;OAKG;IACG,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CASpD;IAED;;OAEG;IACH,OAAO,CAAC,eAAe;IAkBvB;;;;;;;;;;;;;;OAcG;IACG,WAAW,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBtE;IAED;;;;;OAKG;IACH,UAAgB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAqBhD;IAED;;;;;;OAMG;IACG,cAAc,CAChB,OAAO,EAAE,MAAM,GAAG,OAAO,EACzB,OAAO,EAAE,cAAc,GACxB,OAAO,CAAC,IAAI,CAAC,CAuBf;IAED;;;;;;OAMG;IACG,oBAAoB,CACtB,OAAO,GAAE,MAAqB,EAC9B,GAAG,QAAQ,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,IAAI,CAAC,CAUf;CACJ"}
|
|
@@ -11,6 +11,25 @@ export declare class SSRFixture extends CSRFixture {
|
|
|
11
11
|
* Whether the template has been rendered.
|
|
12
12
|
*/
|
|
13
13
|
private templateRendered;
|
|
14
|
+
/**
|
|
15
|
+
* The internal reference to the generated fixture URL.
|
|
16
|
+
*/
|
|
17
|
+
private _url?;
|
|
18
|
+
/**
|
|
19
|
+
* The URL of the generated SSR fixture page. This is set after {@link setTemplate}
|
|
20
|
+
* is called and the page navigates to the generated fixture.
|
|
21
|
+
*/
|
|
22
|
+
get url(): string | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Creates an instance of the SSRFixture.
|
|
25
|
+
*
|
|
26
|
+
* @param page - The Playwright page object.
|
|
27
|
+
* @param tagName - The tag name of the custom element.
|
|
28
|
+
* @param innerHTML - The inner HTML of the custom element.
|
|
29
|
+
* @param waitFor - Additional custom elements to wait for.
|
|
30
|
+
* @param testId - The test ID for the SSR fixture.
|
|
31
|
+
* @param testTitle - The test title for the SSR fixture.
|
|
32
|
+
*/
|
|
14
33
|
constructor(page: Page, tagName: string, innerHTML?: string, waitFor?: string[], testId?: string, testTitle?: string);
|
|
15
34
|
/**
|
|
16
35
|
* Buffers style tags added before {@link setTemplate} so they can be
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-fixture.d.ts","sourceRoot":"","sources":["../../../src/fixtures/ssr-fixture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAEtE,qBAAa,UAAW,SAAQ,UAAU;
|
|
1
|
+
{"version":3,"file":"ssr-fixture.d.ts","sourceRoot":"","sources":["../../../src/fixtures/ssr-fixture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAEtE,qBAAa,UAAW,SAAQ,UAAU;IAuClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;IAvC/B;;OAEG;IACH,OAAO,CAAC,aAAa,CAA4C;IAEjE;;OAEG;IACH,OAAO,CAAC,gBAAgB,CAAS;IAEjC;;OAEG;IACH,OAAO,CAAC,IAAI,CAAC,CAAS;IAEtB;;;OAGG;IACH,IAAW,GAAG,IAAI,MAAM,GAAG,SAAS,CAEnC;IAED;;;;;;;;;OASG;IACH,YACI,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,EACf,SAAS,GAAE,MAAW,EACtB,OAAO,GAAE,MAAM,EAAO,EACL,MAAM,CAAC,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,EAGtC;IAED;;;;;;;OAOG;IACY,WAAW,CACtB,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,GAC5C,OAAO,CAAC,IAAI,CAAC,CAMf;IAED;;;;;;;;;;;OAWG;IACY,WAAW,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqE/E;IAED;;OAEG;IACH,OAAO,CAAC,eAAe;CAqB1B"}
|
package/dist/dts/ssr/render.d.ts
CHANGED
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
* flat exports.
|
|
22
22
|
* ```ts
|
|
23
23
|
* const { render } = createSSRRenderer({
|
|
24
|
-
* tagPrefix: "
|
|
24
|
+
* tagPrefix: "contoso",
|
|
25
25
|
* components: [
|
|
26
|
-
* { name: "button", packageName: "@
|
|
27
|
-
* { name: "checkbox", packageName: "@
|
|
26
|
+
* { name: "button", packageName: "@contoso/button" },
|
|
27
|
+
* { name: "checkbox", packageName: "@contoso/checkbox" },
|
|
28
28
|
* ],
|
|
29
29
|
* });
|
|
30
30
|
* ```
|
|
@@ -37,25 +37,25 @@ export interface ComponentRegistration {
|
|
|
37
37
|
name: string;
|
|
38
38
|
/**
|
|
39
39
|
* The npm package name for this component
|
|
40
|
-
* (e.g., "@
|
|
40
|
+
* (e.g., "@contoso/button").
|
|
41
41
|
*/
|
|
42
42
|
packageName: string;
|
|
43
43
|
}
|
|
44
44
|
export interface SSRRendererOptions {
|
|
45
45
|
/**
|
|
46
|
-
* Tag name prefix for custom elements (e.g., "fluent", "
|
|
46
|
+
* Tag name prefix for custom elements (e.g., "fluent", "contoso").
|
|
47
47
|
*/
|
|
48
48
|
tagPrefix: string;
|
|
49
49
|
/**
|
|
50
50
|
* The npm package name used to resolve component build artifacts
|
|
51
51
|
* when all components live in subdirectories of a single package
|
|
52
|
-
* (
|
|
52
|
+
* (monolithic layout). Mutually exclusive with `components`.
|
|
53
53
|
*/
|
|
54
54
|
packageName?: string;
|
|
55
55
|
/**
|
|
56
|
-
* Explicit list of per-component packages
|
|
57
|
-
*
|
|
58
|
-
*
|
|
56
|
+
* Explicit list of per-component packages. Each entry maps a
|
|
57
|
+
* component name to its npm package. Mutually exclusive with
|
|
58
|
+
* `packageName`.
|
|
59
59
|
*/
|
|
60
60
|
components?: ComponentRegistration[];
|
|
61
61
|
/**
|
|
@@ -82,11 +82,6 @@ export interface RenderResult {
|
|
|
82
82
|
/** Preload link tags (empty string when using fast-build). */
|
|
83
83
|
preloadLinks: string;
|
|
84
84
|
}
|
|
85
|
-
/**
|
|
86
|
-
* Parse a JavaScript default value string from CEM into a JSON-safe value.
|
|
87
|
-
* @internal
|
|
88
|
-
*/
|
|
89
|
-
export declare function parseDefaultValue(raw: string): unknown;
|
|
90
85
|
/**
|
|
91
86
|
* Replace the `{{styles}}` placeholder in an f-template with a
|
|
92
87
|
* stylesheet `<link>` tag. Falls back to injecting after the opening
|
|
@@ -117,9 +112,9 @@ export declare function buildState(queryObj: Record<string, string>): Record<str
|
|
|
117
112
|
*
|
|
118
113
|
* Supports two modes:
|
|
119
114
|
* - **`packageName`**: Scans a monolithic package's dist directory for
|
|
120
|
-
* components in subdirectories (
|
|
115
|
+
* components in subdirectories (monolithic layout).
|
|
121
116
|
* - **`components`**: Uses an explicit list of per-component packages
|
|
122
|
-
* with flat exports
|
|
117
|
+
* with flat exports.
|
|
123
118
|
*/
|
|
124
119
|
export declare function createSSRRenderer(options: SSRRendererOptions): {
|
|
125
120
|
render: (queryObj: Record<string, string>) => RenderResult;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/ssr/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAOH,MAAM,WAAW,qBAAqB;IAClC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IAC/B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,UAAU,CAAC,EAAE,qBAAqB,EAAE,CAAC;IAErC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IACzB,qEAAqE;IACrE,QAAQ,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,YAAY,EAAE,MAAM,CAAC;CACxB;
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/ssr/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAOH,MAAM,WAAW,qBAAqB;IAClC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IAC/B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,UAAU,CAAC,EAAE,qBAAqB,EAAE,CAAC;IAErC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IACzB,qEAAqE;IACrE,QAAQ,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,YAAY,EAAE,MAAM,CAAC;CACxB;AAqFD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAa1E;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAwCvE;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsBpF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG;IAC5D,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,YAAY,CAAC;CAC9D,CA6KA"}
|
|
@@ -29,6 +29,30 @@ function wrapDefaultExpression(expression) {
|
|
|
29
29
|
function attributeDirective(name, value) {
|
|
30
30
|
return `${attributeDirectivePrefix}${name}="${wrapClientExpression(value)}"`;
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Convention-based resolver that loads a companion `*.definition-async.js`
|
|
34
|
+
* module next to the template module and returns its `shadowOptions`.
|
|
35
|
+
*
|
|
36
|
+
* For a template at `dist/textarea/textarea.template.js`, this looks for
|
|
37
|
+
* `dist/textarea/textarea.definition-async.js`.
|
|
38
|
+
*
|
|
39
|
+
* This is the default resolver used by {@link generateFTemplates} and
|
|
40
|
+
* {@link generateWebuiTemplates} when `resolveShadowOptions` is not
|
|
41
|
+
* specified.
|
|
42
|
+
*/
|
|
43
|
+
export async function definitionAsyncResolver(templateJsPath) {
|
|
44
|
+
const dir = path.dirname(templateJsPath);
|
|
45
|
+
const base = path.basename(templateJsPath, ".template.js");
|
|
46
|
+
const defAsyncPath = path.resolve(dir, `${base}.definition-async.js`);
|
|
47
|
+
try {
|
|
48
|
+
const mod = await import(pathToFileURL(defAsyncPath).href);
|
|
49
|
+
const definition = mod.definition ?? mod.default;
|
|
50
|
+
return definition?.shadowOptions;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
32
56
|
/**
|
|
33
57
|
* Extract a readable binding expression from a factory's evaluate function.
|
|
34
58
|
*/
|
|
@@ -195,10 +219,33 @@ export function convertTemplate(viewTemplate, componentName) {
|
|
|
195
219
|
// so the test harness can substitute it with a <link rel="stylesheet"> at
|
|
196
220
|
// render time. Harness fallback auto-injects if the marker is missing, but
|
|
197
221
|
// emitting it explicitly keeps generated output consistent with hand-authored
|
|
198
|
-
// f-templates
|
|
222
|
+
// f-templates.
|
|
199
223
|
fInner = fInner.replace(/(<template[^>]*>)/, `$1${stylesMarker}`);
|
|
200
224
|
return `<f-template name="${componentName}" shadowrootmode="open">\n${fInner}\n</f-template>\n`;
|
|
201
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* Convert a `shadowOptions` object (e.g. `{ delegatesFocus: true }`) into
|
|
228
|
+
* DSD template attribute entries (e.g. `{ shadowrootdelegatesfocus: "" }`).
|
|
229
|
+
*/
|
|
230
|
+
export function shadowOptionsToAttributes(shadowOptions) {
|
|
231
|
+
const attrs = {};
|
|
232
|
+
if (!shadowOptions) {
|
|
233
|
+
return attrs;
|
|
234
|
+
}
|
|
235
|
+
for (const [key, value] of Object.entries(shadowOptions)) {
|
|
236
|
+
if (key === "mode") {
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
const attrName = `shadowroot${key.toLowerCase()}`;
|
|
240
|
+
if (value === true) {
|
|
241
|
+
attrs[attrName] = "";
|
|
242
|
+
}
|
|
243
|
+
else if (typeof value === "string" && value !== "") {
|
|
244
|
+
attrs[attrName] = value;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return attrs;
|
|
248
|
+
}
|
|
202
249
|
export async function generateFTemplates(options = {}) {
|
|
203
250
|
installDomShim();
|
|
204
251
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -220,7 +267,19 @@ export async function generateFTemplates(options = {}) {
|
|
|
220
267
|
if (!fTemplateHtml) {
|
|
221
268
|
continue;
|
|
222
269
|
}
|
|
270
|
+
// Resolve shadow options and inject them into the <f-template> tag.
|
|
271
|
+
const resolver = options.resolveShadowOptions === null
|
|
272
|
+
? undefined
|
|
273
|
+
: (options.resolveShadowOptions ?? definitionAsyncResolver);
|
|
274
|
+
const shadowOpts = resolver ? await resolver(jsFilePath) : undefined;
|
|
275
|
+
const shadowAttrs = shadowOptionsToAttributes(shadowOpts);
|
|
223
276
|
let html = fTemplateHtml;
|
|
277
|
+
if (Object.keys(shadowAttrs).length > 0) {
|
|
278
|
+
const extraAttrs = Object.entries(shadowAttrs)
|
|
279
|
+
.map(([k, v]) => (v ? ` ${k}="${v}"` : ` ${k}`))
|
|
280
|
+
.join("");
|
|
281
|
+
html = html.replace(/(<f-template[^>]*)(>)/, `$1${extraAttrs}$2`);
|
|
282
|
+
}
|
|
224
283
|
if (options.format) {
|
|
225
284
|
try {
|
|
226
285
|
html = await options.format(html, jsFilePath);
|
|
@@ -229,8 +288,9 @@ export async function generateFTemplates(options = {}) {
|
|
|
229
288
|
console.warn(styleText(["yellow", "bold"], "⚠"), `Format failed for ${componentName}:`, formatError.message);
|
|
230
289
|
}
|
|
231
290
|
}
|
|
291
|
+
const relativeDir = path.relative(distDir, path.dirname(jsFilePath));
|
|
232
292
|
const fTemplatePath = outDir
|
|
233
|
-
? path.resolve(outDir, `${componentBaseName}.template.html`)
|
|
293
|
+
? path.resolve(outDir, relativeDir, `${componentBaseName}.template.html`)
|
|
234
294
|
: path.resolve(path.dirname(jsFilePath), `${componentBaseName}.template.html`);
|
|
235
295
|
await mkdir(path.dirname(fTemplatePath), { recursive: true });
|
|
236
296
|
await writeFile(fTemplatePath, html, "utf8");
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* ```ts
|
|
15
15
|
* import { generateWebuiTemplates } from "@microsoft/fast-test-harness/build/generate-webui-templates.js";
|
|
16
16
|
*
|
|
17
|
-
* await generateWebuiTemplates({ cwd: process.cwd(), tagPrefix: "
|
|
17
|
+
* await generateWebuiTemplates({ cwd: process.cwd(), tagPrefix: "contoso" });
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
20
|
import { glob, mkdir, writeFile } from "node:fs/promises";
|
|
@@ -23,31 +23,9 @@ import { pathToFileURL } from "node:url";
|
|
|
23
23
|
import { styleText } from "node:util";
|
|
24
24
|
import { closeExpression, openExpression } from "@microsoft/fast-html/syntax.js";
|
|
25
25
|
import { installDomShim } from "./dom-shim.js";
|
|
26
|
-
import { convertTemplate } from "./generate-templates.js";
|
|
26
|
+
import { convertTemplate, definitionAsyncResolver, shadowOptionsToAttributes, } from "./generate-templates.js";
|
|
27
27
|
const stylesMarker = `${openExpression}styles${closeExpression}`;
|
|
28
28
|
const escapedStylesMarker = new RegExp(stylesMarker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g");
|
|
29
|
-
/**
|
|
30
|
-
* Try to load shadow options from a companion `*.definition-async.js`
|
|
31
|
-
* module next to the template module. Returns an object with template
|
|
32
|
-
* attribute strings to add (e.g. `shadowrootdelegatesfocus`).
|
|
33
|
-
*/
|
|
34
|
-
async function loadShadowAttributes(templateJsPath) {
|
|
35
|
-
const dir = path.dirname(templateJsPath);
|
|
36
|
-
const base = path.basename(templateJsPath, ".template.js");
|
|
37
|
-
const defAsyncPath = path.resolve(dir, `${base}.definition-async.js`);
|
|
38
|
-
const attrs = {};
|
|
39
|
-
try {
|
|
40
|
-
const mod = await import(pathToFileURL(defAsyncPath).href);
|
|
41
|
-
const definition = mod.definition ?? mod.default;
|
|
42
|
-
if (definition?.shadowOptions?.delegatesFocus) {
|
|
43
|
-
attrs.shadowrootdelegatesfocus = "";
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
catch {
|
|
47
|
-
// No definition-async module or it failed to load — skip.
|
|
48
|
-
}
|
|
49
|
-
return attrs;
|
|
50
|
-
}
|
|
51
29
|
/**
|
|
52
30
|
* Transform an f-template string into a webui template by replacing the
|
|
53
31
|
* `<f-template>` wrapper with `<template shadowrootmode="open">` and
|
|
@@ -97,7 +75,11 @@ export async function generateWebuiTemplates(options = {}) {
|
|
|
97
75
|
if (!fTemplateHtml) {
|
|
98
76
|
continue;
|
|
99
77
|
}
|
|
100
|
-
const
|
|
78
|
+
const resolver = options.resolveShadowOptions === null
|
|
79
|
+
? undefined
|
|
80
|
+
: (options.resolveShadowOptions ?? definitionAsyncResolver);
|
|
81
|
+
const shadowOpts = resolver ? await resolver(jsFilePath) : undefined;
|
|
82
|
+
const shadowAttrs = shadowOptionsToAttributes(shadowOpts);
|
|
101
83
|
let html = fTemplateToWebui(fTemplateHtml, shadowAttrs);
|
|
102
84
|
if (options.format) {
|
|
103
85
|
try {
|
|
@@ -107,8 +89,9 @@ export async function generateWebuiTemplates(options = {}) {
|
|
|
107
89
|
console.warn(styleText(["yellow", "bold"], "⚠"), `Format failed for ${componentName}:`, formatError.message);
|
|
108
90
|
}
|
|
109
91
|
}
|
|
92
|
+
const relativeDir = path.relative(distDir, path.dirname(jsFilePath));
|
|
110
93
|
const webuiPath = outDir
|
|
111
|
-
? path.resolve(outDir, `${componentBaseName}.template-webui.html`)
|
|
94
|
+
? path.resolve(outDir, relativeDir, `${componentBaseName}.template-webui.html`)
|
|
112
95
|
: path.resolve(path.dirname(jsFilePath), `${componentBaseName}.template-webui.html`);
|
|
113
96
|
await mkdir(path.dirname(webuiPath), { recursive: true });
|
|
114
97
|
await writeFile(webuiPath, html, "utf8");
|
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
import { CSRFixture } from "./csr-fixture.js";
|
|
2
2
|
export class SSRFixture extends CSRFixture {
|
|
3
|
+
/**
|
|
4
|
+
* The URL of the generated SSR fixture page. This is set after {@link setTemplate}
|
|
5
|
+
* is called and the page navigates to the generated fixture.
|
|
6
|
+
*/
|
|
7
|
+
get url() {
|
|
8
|
+
return this._url;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Creates an instance of the SSRFixture.
|
|
12
|
+
*
|
|
13
|
+
* @param page - The Playwright page object.
|
|
14
|
+
* @param tagName - The tag name of the custom element.
|
|
15
|
+
* @param innerHTML - The inner HTML of the custom element.
|
|
16
|
+
* @param waitFor - Additional custom elements to wait for.
|
|
17
|
+
* @param testId - The test ID for the SSR fixture.
|
|
18
|
+
* @param testTitle - The test title for the SSR fixture.
|
|
19
|
+
*/
|
|
3
20
|
constructor(page, tagName, innerHTML = "", waitFor = [], testId, testTitle) {
|
|
4
21
|
super(page, tagName, innerHTML, waitFor);
|
|
5
22
|
this.testId = testId;
|
|
@@ -86,7 +103,8 @@ export class SSRFixture extends CSRFixture {
|
|
|
86
103
|
if (!result.url) {
|
|
87
104
|
throw new Error(`Invalid response from server: ${JSON.stringify(result)}`);
|
|
88
105
|
}
|
|
89
|
-
|
|
106
|
+
this._url = result.url;
|
|
107
|
+
await this.page.goto(this._url);
|
|
90
108
|
await this.waitForStability();
|
|
91
109
|
this.templateRendered = true;
|
|
92
110
|
this.pendingStyles.length = 0;
|