@aurelia/storybook 2.1.0 → 2.2.1

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.
Files changed (108) hide show
  1. package/.github/workflows/ci.yml +61 -0
  2. package/.github/workflows/publish.yml +82 -0
  3. package/.github/workflows/storybook-preview.yml +62 -0
  4. package/CHANGELOG.md +5 -0
  5. package/README.md +180 -1
  6. package/__tests__/create-aurelia-app.test.ts +94 -0
  7. package/__tests__/preset.test.ts +32 -3
  8. package/__tests__/preview.test.ts +9 -131
  9. package/__tests__/render.test.ts +15 -26
  10. package/apps/hello-world/package-lock.json +404 -287
  11. package/apps/hello-world/package.json +10 -10
  12. package/apps/hello-world/src/components/notification-center.ts +2 -2
  13. package/apps/hello-world/src/components/stat-card.ts +12 -4
  14. package/apps/hello-world/src/components/weather-widget.ts +2 -1
  15. package/apps/hello-world/src/stories/feedback-form.stories.ts +15 -9
  16. package/apps/hello-world/src/stories/hello-world.stories.ts +20 -9
  17. package/apps/hello-world/src/stories/notification-center.stories.ts +17 -10
  18. package/apps/hello-world/src/stories/stat-card.stories.ts +23 -13
  19. package/apps/hello-world/src/stories/weather-widget.stories.ts +18 -13
  20. package/apps/hello-world-rsbuild/.storybook/main.ts +16 -0
  21. package/apps/hello-world-rsbuild/.storybook/preview.ts +1 -0
  22. package/apps/hello-world-rsbuild/.stylelintrc.json +5 -0
  23. package/apps/hello-world-rsbuild/README.md +28 -0
  24. package/apps/hello-world-rsbuild/eslint.config.mjs +25 -0
  25. package/apps/hello-world-rsbuild/favicon.ico +0 -0
  26. package/apps/hello-world-rsbuild/index.html +17 -0
  27. package/apps/hello-world-rsbuild/package-lock.json +11131 -0
  28. package/apps/hello-world-rsbuild/package.json +56 -0
  29. package/apps/hello-world-rsbuild/src/components/feedback-form.html +111 -0
  30. package/apps/hello-world-rsbuild/src/components/feedback-form.ts +45 -0
  31. package/apps/hello-world-rsbuild/src/components/notification-center.html +119 -0
  32. package/apps/hello-world-rsbuild/src/components/notification-center.ts +27 -0
  33. package/apps/hello-world-rsbuild/src/components/stat-card.html +107 -0
  34. package/apps/hello-world-rsbuild/src/components/stat-card.ts +41 -0
  35. package/apps/hello-world-rsbuild/src/components/weather-widget.html +89 -0
  36. package/apps/hello-world-rsbuild/src/components/weather-widget.ts +31 -0
  37. package/apps/hello-world-rsbuild/src/hello-world.html +48 -0
  38. package/apps/hello-world-rsbuild/src/hello-world.ts +17 -0
  39. package/apps/hello-world-rsbuild/src/main.ts +6 -0
  40. package/apps/hello-world-rsbuild/src/my-app.html +1 -0
  41. package/apps/hello-world-rsbuild/src/my-app.ts +3 -0
  42. package/apps/hello-world-rsbuild/src/resource.d.ts +15 -0
  43. package/apps/hello-world-rsbuild/src/services/weather-service.ts +15 -0
  44. package/apps/hello-world-rsbuild/src/stories/feedback-form.stories.ts +58 -0
  45. package/apps/hello-world-rsbuild/src/stories/hello-world.stories.ts +64 -0
  46. package/apps/hello-world-rsbuild/src/stories/notification-center.stories.ts +88 -0
  47. package/apps/hello-world-rsbuild/src/stories/stat-card.stories.ts +75 -0
  48. package/apps/hello-world-rsbuild/src/stories/weather-widget.stories.ts +62 -0
  49. package/apps/hello-world-rsbuild/test/my-app.spec.ts +15 -0
  50. package/apps/hello-world-rsbuild/test/setup.ts +29 -0
  51. package/apps/hello-world-rsbuild/tsconfig.json +19 -0
  52. package/apps/hello-world-rsbuild/tsconfig.vitest.json +11 -0
  53. package/apps/hello-world-rsbuild/vite.config.ts +17 -0
  54. package/apps/hello-world-rsbuild/vitest.config.ts +15 -0
  55. package/apps/hello-world-webpack/package-lock.json +239 -264
  56. package/apps/hello-world-webpack/package.json +8 -7
  57. package/apps/hello-world-webpack/src/components/notification-center.ts +2 -2
  58. package/apps/hello-world-webpack/src/components/stat-card.ts +12 -4
  59. package/apps/hello-world-webpack/src/components/weather-widget.ts +2 -1
  60. package/apps/hello-world-webpack/src/my-app.stories.ts +6 -4
  61. package/apps/hello-world-webpack/src/stories/feedback-form.stories.ts +15 -9
  62. package/apps/hello-world-webpack/src/stories/hello-world.stories.ts +20 -9
  63. package/apps/hello-world-webpack/src/stories/notification-center.stories.ts +17 -10
  64. package/apps/hello-world-webpack/src/stories/stat-card.stories.ts +23 -13
  65. package/apps/hello-world-webpack/src/stories/weather-widget.stories.ts +18 -13
  66. package/dist/index.d.ts +25 -0
  67. package/dist/index.js +68 -14
  68. package/dist/index.js.map +1 -1
  69. package/dist/preset.d.ts +21 -0
  70. package/dist/preset.js +46 -2
  71. package/dist/preset.js.map +1 -1
  72. package/dist/preview/helpers.d.ts +2 -0
  73. package/dist/preview/helpers.js +6 -0
  74. package/dist/preview/helpers.js.map +1 -0
  75. package/dist/preview/render.d.ts +7 -0
  76. package/dist/preview/render.js +66 -15
  77. package/dist/preview/render.js.map +1 -1
  78. package/dist/preview/storybook-types-runtime.d.ts +1 -0
  79. package/dist/preview/storybook-types-runtime.js +5 -0
  80. package/dist/preview/storybook-types-runtime.js.map +1 -0
  81. package/dist/preview/storybook-types.d.ts +27 -0
  82. package/dist/preview/types-runtime.d.ts +1 -0
  83. package/dist/preview/types-runtime.js +5 -0
  84. package/dist/preview/types-runtime.js.map +1 -0
  85. package/dist/preview/types.d.ts +44 -0
  86. package/dist/preview.d.ts +3 -0
  87. package/dist/preview.js +71 -16
  88. package/dist/preview.js.map +1 -1
  89. package/dist/webpack.d.ts +10 -0
  90. package/dist/webpack.js +19 -1
  91. package/dist/webpack.js.map +1 -1
  92. package/package.json +54 -9
  93. package/rollup.config.mjs +5 -3
  94. package/scripts/sync-versions.cjs +55 -0
  95. package/src/index.ts +11 -1
  96. package/src/preset.ts +32 -2
  97. package/src/preview/helpers.ts +7 -0
  98. package/src/preview/render.ts +98 -30
  99. package/src/preview/storybook-types-runtime.ts +2 -0
  100. package/src/preview/storybook-types.ts +34 -0
  101. package/src/preview/types-runtime.ts +2 -0
  102. package/src/preview/types.ts +57 -2
  103. package/src/preview.ts +11 -1
  104. package/src/webpack.ts +19 -0
  105. package/CONTINUITY.md +0 -22
  106. package/dist/preview/types.js +0 -2
  107. package/dist/preview/types.js.map +0 -1
  108. /package/{jest.config.js → jest.config.cjs} +0 -0
@@ -0,0 +1,61 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ build:
9
+ runs-on: ubuntu-latest
10
+
11
+ steps:
12
+ - name: Checkout
13
+ uses: actions/checkout@v4
14
+
15
+ - name: Setup Node
16
+ uses: actions/setup-node@v4
17
+ with:
18
+ node-version: 20.19.0
19
+ cache: npm
20
+
21
+ - name: Install root deps
22
+ run: npm install
23
+
24
+ - name: Verify example versions are aligned
25
+ run: npm run sync:versions:check
26
+
27
+ - name: Build package
28
+ run: npm run build
29
+
30
+ - name: Build types
31
+ run: npm run build:types
32
+
33
+ - name: Test package
34
+ run: npm test
35
+
36
+ - name: Build hello-world (Vite)
37
+ working-directory: apps/hello-world
38
+ run: |
39
+ npm pkg set "devDependencies.@aurelia/storybook=file:../.."
40
+ npm install
41
+ npx tsc --noEmit -p tsconfig.json
42
+ npm run build
43
+ npm run build-storybook
44
+
45
+ - name: Build hello-world-webpack
46
+ working-directory: apps/hello-world-webpack
47
+ run: |
48
+ npm pkg set "devDependencies.@aurelia/storybook=file:../.."
49
+ npm install
50
+ npx tsc --noEmit -p tsconfig.json
51
+ npm run build
52
+ npm run build-storybook
53
+
54
+ - name: Build hello-world-rsbuild
55
+ working-directory: apps/hello-world-rsbuild
56
+ run: |
57
+ npm pkg set "devDependencies.@aurelia/storybook=file:../.."
58
+ npm install
59
+ npx tsc --noEmit -p tsconfig.json
60
+ npm run build
61
+ npm run build-storybook
@@ -0,0 +1,82 @@
1
+ name: Publish
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+ workflow_dispatch:
8
+ inputs:
9
+ tag:
10
+ description: 'Tag to publish (e.g., v2.2.1)'
11
+ required: true
12
+ type: string
13
+
14
+ jobs:
15
+ publish:
16
+ runs-on: ubuntu-latest
17
+ permissions:
18
+ contents: read
19
+ id-token: write
20
+
21
+ steps:
22
+ - name: Checkout
23
+ uses: actions/checkout@v4
24
+ with:
25
+ ref: ${{ inputs.tag || github.ref }}
26
+
27
+ - name: Setup Node
28
+ uses: actions/setup-node@v4
29
+ with:
30
+ node-version: 20.19.0
31
+ registry-url: https://registry.npmjs.org
32
+ cache: npm
33
+
34
+ - name: Install deps
35
+ run: npm install
36
+
37
+ - name: Verify versions aligned
38
+ run: npm run sync:versions:check
39
+
40
+ - name: Verify tag matches package version
41
+ run: |
42
+ TAG_INPUT="${{ inputs.tag }}"
43
+ if [ -n "$TAG_INPUT" ]; then
44
+ TAG="${TAG_INPUT#v}"
45
+ else
46
+ TAG="${GITHUB_REF_NAME#v}"
47
+ fi
48
+ VERSION="$(node -p "require('./package.json').version")"
49
+ if [ "$TAG" != "$VERSION" ]; then
50
+ echo "Tag ($TAG) does not match package.json version ($VERSION)"
51
+ exit 1
52
+ fi
53
+
54
+ - name: Build package
55
+ run: npm run build
56
+
57
+ - name: Build types
58
+ run: npm run build:types
59
+
60
+ - name: Test package
61
+ run: npm test
62
+
63
+ - name: Verify changelog exists
64
+ run: |
65
+ if [ ! -s CHANGELOG.md ]; then
66
+ echo "CHANGELOG.md is empty. Run npm run changelog before tagging."
67
+ exit 1
68
+ fi
69
+
70
+ - name: Verify changelog version matches package
71
+ run: |
72
+ VERSION="$(node -p "require('./package.json').version")"
73
+ CHANGELOG_VERSION="$(node -e "const fs=require('fs');const m=fs.readFileSync('CHANGELOG.md','utf8').match(/## \\[(\\d+\\.\\d+\\.\\d+(?:-[^\\]]+)?)\\]/);console.log(m?m[1]:'')")"
74
+ if [ "$VERSION" != "$CHANGELOG_VERSION" ]; then
75
+ echo "CHANGELOG.md latest version ($CHANGELOG_VERSION) does not match package.json ($VERSION)"
76
+ exit 1
77
+ fi
78
+
79
+ - name: Publish to npm
80
+ run: npm publish --access public
81
+ env:
82
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -0,0 +1,62 @@
1
+ name: Storybook Preview
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+ pages: write
12
+ id-token: write
13
+
14
+ concurrency:
15
+ group: pages
16
+ cancel-in-progress: true
17
+
18
+ jobs:
19
+ build:
20
+ runs-on: ubuntu-latest
21
+
22
+ steps:
23
+ - name: Checkout
24
+ uses: actions/checkout@v4
25
+
26
+ - name: Setup Node
27
+ uses: actions/setup-node@v4
28
+ with:
29
+ node-version: 20.19.0
30
+ cache: npm
31
+
32
+ - name: Install root deps
33
+ run: npm install
34
+
35
+ - name: Build package
36
+ run: npm run build
37
+
38
+ - name: Build Storybook (hello-world)
39
+ working-directory: apps/hello-world
40
+ run: |
41
+ npm pkg set "devDependencies.@aurelia/storybook=file:../.."
42
+ npm install
43
+ npm run build-storybook
44
+
45
+ - name: Configure Pages
46
+ uses: actions/configure-pages@v5
47
+
48
+ - name: Upload Pages artifact
49
+ uses: actions/upload-pages-artifact@v3
50
+ with:
51
+ path: apps/hello-world/storybook-static
52
+
53
+ deploy:
54
+ runs-on: ubuntu-latest
55
+ needs: build
56
+ environment:
57
+ name: github-pages
58
+ url: ${{ steps.deployment.outputs.page_url }}
59
+ steps:
60
+ - name: Deploy to GitHub Pages
61
+ id: deployment
62
+ uses: actions/deploy-pages@v4
package/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [2.2.1](https://github.com/aurelia/storybook/compare/2.1.0...2.2.1) (2026-01-23)
2
+
3
+ ### Features
4
+
5
+ * **storybook:** update packages, tooling, rsbuild support ([3a97a99](https://github.com/aurelia/storybook/commit/3a97a9950693183b5880756a943e620895f9457b))
package/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
  | --- | --- | --- |
11
11
  | Storybook | 10.x (ESM) | Tested with 10.0.5+; works with `storybook dev`/`storybook build` commands. |
12
12
  | Aurelia | 2.0.0-beta.25+ | Uses Aurelia's `enhance()` APIs under the hood. |
13
- | Bundlers | `@storybook/builder-vite` (Vite 5) · `@storybook/builder-webpack5` | Pick whichever matches your app; both share the same Aurelia preview runtime. |
13
+ | Bundlers | `@storybook/builder-vite` (Vite 5) · `@storybook/builder-webpack5` · `storybook-builder-rsbuild` (Rsbuild/Rspack) | Pick whichever matches your app; they share the same Aurelia preview runtime. |
14
14
  | Node.js | ≥ 20.19.0 or ≥ 22.12.0 | Matches the engines field in `package.json` and Storybook 10's baseline.
15
15
 
16
16
  ## Requirements
@@ -25,6 +25,8 @@
25
25
  npm install --save-dev @aurelia/storybook storybook @storybook/builder-vite
26
26
  # or, for Webpack builds:
27
27
  npm install --save-dev @aurelia/storybook storybook @storybook/builder-webpack5
28
+ # or, for Rsbuild/Rspack builds:
29
+ npm install --save-dev @aurelia/storybook storybook storybook-builder-rsbuild @rsbuild/core
28
30
  ```
29
31
 
30
32
  Add whichever addons you need (`@storybook/addon-links`, `@storybook/addon-actions`, etc.). Essentials functionality now ships with Storybook 10 core, so most projects only add optional extras.
@@ -119,6 +121,37 @@ Add whichever addons you need (`@storybook/addon-links`, `@storybook/addon-actio
119
121
 
120
122
  ---
121
123
 
124
+ ## Quick Start (Rsbuild/Rspack Builder)
125
+
126
+ 1. Install `storybook-builder-rsbuild` and `@rsbuild/core`.
127
+ 2. Create `.storybook/main.ts`:
128
+
129
+ ```ts
130
+ import type { StorybookConfig } from 'storybook/internal/types';
131
+
132
+ const config: StorybookConfig = {
133
+ stories: ['../src/**/*.stories.@(ts|tsx|js|jsx|mdx)'],
134
+ addons: ['@storybook/addon-links'],
135
+ framework: {
136
+ name: '@aurelia/storybook',
137
+ options: {},
138
+ },
139
+ core: {
140
+ builder: 'storybook-builder-rsbuild',
141
+ },
142
+ };
143
+
144
+ export default config;
145
+ ```
146
+
147
+ The Aurelia preset injects the `ts-loader` + `@aurelia/webpack-loader` rules via `rsbuildFinal`,
148
+ so most projects do not need extra Rsbuild configuration. If you do, add your own `rsbuildFinal`
149
+ and merge with `@rsbuild/core`'s `mergeRsbuildConfig`.
150
+
151
+ 3. Reuse the same `.storybook/preview.ts` and `package.json` scripts as in the Vite quick start.
152
+
153
+ ---
154
+
122
155
  ## Writing Aurelia Stories
123
156
 
124
157
  Story files look exactly like standard Storybook CSF stories. The framework export automatically:
@@ -178,6 +211,22 @@ export const WithCustomTemplate = {
178
211
  };
179
212
  ```
180
213
 
214
+ ### Helper for Typed Story Results
215
+
216
+ If you want stronger typing (especially for `props`), you can use the helper and types exported by the package:
217
+
218
+ ```ts
219
+ import { defineAureliaStory, type AureliaStoryResult } from '@aurelia/storybook';
220
+
221
+ const render = (args: { title: string }): AureliaStoryResult<{ title: string }> =>
222
+ defineAureliaStory({
223
+ template: `<my-card title.bind="title"></my-card>`,
224
+ props: args,
225
+ });
226
+ ```
227
+
228
+ You can also import directly from `@aurelia/storybook/preview` or `@aurelia/storybook/preview/types` if you prefer.
229
+
181
230
  ### Story Result Contract
182
231
 
183
232
  When you provide a custom `render` function, return an object with any of the following fields. The Aurelia runtime consumes them while creating the preview app:
@@ -220,6 +269,117 @@ export const WithServices = {
220
269
 
221
270
  Because the Aurelia app lives for the lifetime of the story iframe, DI registrations persist until the story is torn down or Storybook forces a remount. If you need a clean state between stories, set `parameters: { forceRemount: true }` on the story or click the *Remount component* toolbar button in Storybook.
222
271
 
272
+ ### Global Aurelia Configuration (Preview + Story Parameters)
273
+
274
+ You can register global resources/plugins and customize the DI container via Storybook parameters. The framework reads `parameters.aurelia` from the merged Storybook context (preview + component + story):
275
+
276
+ ```ts
277
+ // .storybook/preview.ts
278
+ import { Registration } from 'aurelia';
279
+ import { CurrencyValueConverter } from '../src/resources/currency';
280
+ import { FeatureFlags } from '../src/services/feature-flags';
281
+
282
+ export const parameters = {
283
+ aurelia: {
284
+ register: [CurrencyValueConverter],
285
+ configureContainer: (container) => {
286
+ container.register(Registration.instance(FeatureFlags, { beta: true }));
287
+ },
288
+ },
289
+ };
290
+ ```
291
+
292
+ You can also override or extend per story:
293
+
294
+ ```ts
295
+ export const WithOverrides = {
296
+ parameters: {
297
+ aurelia: {
298
+ configureContainer: (container) => {
299
+ container.register(Registration.instance('apiBaseUrl', 'https://staging.example.com'));
300
+ },
301
+ },
302
+ },
303
+ };
304
+ ```
305
+
306
+ These hooks run when the Aurelia app is created. If you rely on different container setups per story, use `parameters: { forceRemount: true }` to ensure a fresh app instance.
307
+
308
+ #### Parameters API (Quick Reference)
309
+
310
+ ```ts
311
+ export const parameters = {
312
+ aurelia: {
313
+ // Register global resources/plugins
314
+ register: [MyElement, MyValueConverter],
315
+ // Optional aliases for parity with story results
316
+ components: [MyElement],
317
+ items: [Registration.instance(MyService, new MyService())],
318
+ // Configure the DI container
319
+ configureContainer: (container, context) => {
320
+ // ...
321
+ },
322
+ // Configure the Aurelia instance
323
+ configure: (aurelia, context) => {
324
+ // ...
325
+ },
326
+ },
327
+ };
328
+ ```
329
+
330
+ ## Cookbook
331
+
332
+ ### 1) Register global resources once
333
+
334
+ ```ts
335
+ // .storybook/preview.ts
336
+ import { Registration } from 'aurelia';
337
+ import { CurrencyValueConverter } from '../src/resources/currency';
338
+ import { FeatureFlags } from '../src/services/feature-flags';
339
+
340
+ export const parameters = {
341
+ aurelia: {
342
+ register: [CurrencyValueConverter],
343
+ configureContainer: (container) => {
344
+ container.register(Registration.instance(FeatureFlags, { beta: true }));
345
+ },
346
+ },
347
+ };
348
+ ```
349
+
350
+ ### 2) Mock a service per story
351
+
352
+ ```ts
353
+ import { Registration } from 'aurelia';
354
+ import { IWeatherService } from '../src/services/weather-service';
355
+
356
+ export const WithMockedService = {
357
+ render: (args) =>
358
+ defineAureliaStory({
359
+ template: `<weather-widget location.bind="location"></weather-widget>`,
360
+ props: args,
361
+ items: [
362
+ Registration.instance(IWeatherService, {
363
+ getWeather: async () => ({ location: 'Seattle', condition: 'Sunny' }),
364
+ }),
365
+ ],
366
+ }),
367
+ };
368
+ ```
369
+
370
+ ### 3) Force a clean DI container per story
371
+
372
+ ```ts
373
+ export const CleanState = {
374
+ parameters: { forceRemount: true },
375
+ render: (args) =>
376
+ defineAureliaStory({
377
+ template: `<my-component value.bind="value"></my-component>`,
378
+ props: args,
379
+ }),
380
+ };
381
+ ```
382
+
223
383
  ## Example Apps Inside This Repo
224
384
 
225
385
  - `apps/hello-world` – Vite-based Aurelia starter that consumes `@aurelia/storybook`.
@@ -265,6 +425,25 @@ This repository publishes the Storybook framework itself. Helpful scripts:
265
425
 
266
426
  While developing, you can link the package into one of the sample apps in `apps/` to manual-test Storybook changes end to end.
267
427
 
428
+ ## Releases & Changelog
429
+
430
+ - Keep `CHANGELOG.md` updated for each release (use the **Unreleased** section while working).
431
+ - Align example app versions with the root package before tagging:
432
+ - `npm run sync:versions`
433
+ - Tag releases as `vX.Y.Z` so the publish workflow can run.
434
+
435
+ Publish flow (automated via GitHub Actions):
436
+ 1. Update `package.json` version.
437
+ 2. Generate `CHANGELOG.md` from conventional commits: `npm run changelog`.
438
+ 3. Run `npm run sync:versions` and commit changes.
439
+ 4. Create tag `vX.Y.Z` and push it.
440
+
441
+ ## Troubleshooting
442
+
443
+ - **AUR0153 duplicate element registration**: ensure the same component isn't registered multiple times within the same story/container.
444
+ - **Args undefined during first render**: defensively handle optional args in components (e.g., fallbacks for arrays/strings).
445
+ - **Rsbuild `loader.loadModule is not a function`**: avoid `ts-loader` in Rsbuild/Rspack builds; use the built-in Rsbuild TS handling.
446
+
268
447
  ## Contributing
269
448
 
270
449
  Bug reports, docs tweaks, and feature PRs are all welcome. Please open an issue to discuss significant changes, and spin up one of the example apps to verify the behavior you are touching.
@@ -0,0 +1,94 @@
1
+ import { createAureliaApp } from '../src/preview/render';
2
+
3
+ jest.mock('aurelia', () => {
4
+ let lastInstance: any;
5
+
6
+ class Aurelia {
7
+ public container: { has: jest.Mock };
8
+ public register = jest.fn();
9
+ public app = jest.fn(() => ({}));
10
+
11
+ constructor(container?: unknown) {
12
+ this.container = (container as any) ?? { has: jest.fn(() => false) };
13
+ lastInstance = this;
14
+ }
15
+ }
16
+
17
+ const CustomElement = {
18
+ define: jest.fn((definition: unknown, Type: new () => unknown) => Type),
19
+ getDefinition: jest.fn(() => ({ name: 'dummy', bindables: {}, key: 'au:ce:dummy' })),
20
+ isType: jest.fn(() => true),
21
+ };
22
+
23
+ return {
24
+ __esModule: true,
25
+ default: Aurelia,
26
+ CustomElement,
27
+ __getLastInstance: () => lastInstance,
28
+ };
29
+ });
30
+
31
+ describe('createAureliaApp', () => {
32
+ it('does not double-register the component when included in components', () => {
33
+ const Component = class {};
34
+ const host = document.createElement('div');
35
+
36
+ createAureliaApp(
37
+ { template: '<dummy></dummy>', components: [Component] } as any,
38
+ {},
39
+ host,
40
+ Component as any
41
+ );
42
+
43
+ const aurelia = (jest.requireMock('aurelia') as any).__getLastInstance();
44
+ const registerArgs = aurelia.register.mock.calls.flat();
45
+ const registrations = registerArgs.filter((entry: unknown) => entry === Component);
46
+ expect(registrations).toHaveLength(1);
47
+ });
48
+
49
+ it('skips registration when the container already has the component key', () => {
50
+ const Component = class {};
51
+ const host = document.createElement('div');
52
+ const container = { has: jest.fn(() => true) };
53
+
54
+ createAureliaApp(
55
+ { template: '<dummy></dummy>', components: [] as any, container } as any,
56
+ {},
57
+ host,
58
+ Component as any
59
+ );
60
+
61
+ const aurelia = (jest.requireMock('aurelia') as any).__getLastInstance();
62
+ expect(container.has).toHaveBeenCalled();
63
+ expect(aurelia.register).not.toHaveBeenCalled();
64
+ });
65
+
66
+ it('applies parameters.aurelia registrations and hooks', () => {
67
+ const GlobalComponent = class {};
68
+ const host = document.createElement('div');
69
+ const configureContainer = jest.fn();
70
+ const configure = jest.fn();
71
+ const storyContext = {
72
+ parameters: {
73
+ aurelia: {
74
+ register: [GlobalComponent],
75
+ configureContainer,
76
+ configure,
77
+ },
78
+ },
79
+ } as any;
80
+
81
+ createAureliaApp(
82
+ { template: '<dummy></dummy>' } as any,
83
+ {},
84
+ host,
85
+ undefined,
86
+ storyContext
87
+ );
88
+
89
+ const aurelia = (jest.requireMock('aurelia') as any).__getLastInstance();
90
+ expect(configureContainer).toHaveBeenCalledWith(aurelia.container, storyContext);
91
+ expect(aurelia.register).toHaveBeenCalledWith(GlobalComponent);
92
+ expect(configure).toHaveBeenCalledWith(aurelia, storyContext);
93
+ });
94
+ });
@@ -1,11 +1,28 @@
1
- import { webpackFinal, viteFinal } from '../src/preset';
2
- import { getRules } from '../src/webpack';
1
+ import { rsbuildFinal, webpackFinal, viteFinal } from '../src/preset';
2
+ import { getRsbuildRules, getRules } from '../src/webpack';
3
3
 
4
4
  jest.mock('../src/webpack', () => ({
5
5
  getRules: jest.fn(() => [
6
6
  { test: /\.ts$/, use: 'ts-loader' },
7
7
  { test: /\.html$/, use: 'html-loader' },
8
8
  ]),
9
+ getRsbuildRules: jest.fn(() => [
10
+ { test: /\.ts$/, use: '@aurelia/webpack-loader' },
11
+ { test: /\.html$/, use: '@aurelia/webpack-loader' },
12
+ ]),
13
+ }));
14
+
15
+ const mergeRsbuildConfig = jest.fn((base, extra) => ({
16
+ ...base,
17
+ ...extra,
18
+ tools: {
19
+ ...base?.tools,
20
+ ...extra?.tools,
21
+ },
22
+ }));
23
+
24
+ jest.mock('@rsbuild/core', () => ({
25
+ mergeRsbuildConfig,
9
26
  }));
10
27
 
11
28
  describe('preset', () => {
@@ -46,4 +63,16 @@ describe('preset', () => {
46
63
  expect(result).toBe(config);
47
64
  });
48
65
  });
49
- });
66
+
67
+ describe('rsbuildFinal', () => {
68
+ it('should merge rsbuild config and add Aurelia rules', async () => {
69
+ const config = { tools: {} };
70
+ const result = await rsbuildFinal(config);
71
+ expect(mergeRsbuildConfig).toHaveBeenCalledWith(config, expect.any(Object));
72
+
73
+ const rspackConfig = { module: { rules: [] as any[] } };
74
+ result.tools.rspack(rspackConfig);
75
+ expect(rspackConfig.module.rules).toEqual(getRsbuildRules());
76
+ });
77
+ });
78
+ });