@aurelia/storybook 0.1.1 → 1.0.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.
Files changed (73) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +31 -3
  3. package/__tests__/preset.test.ts +49 -0
  4. package/__tests__/preview.test.ts +139 -0
  5. package/__tests__/render.test.ts +0 -1
  6. package/__tests__/webpack.test.ts +21 -0
  7. package/apps/hello-world/.storybook/main.ts +30 -0
  8. package/apps/hello-world/.storybook/preview.ts +1 -0
  9. package/apps/hello-world/.stylelintrc.json +5 -0
  10. package/apps/hello-world/.yarnrc.yml +2 -0
  11. package/apps/hello-world/README.md +28 -0
  12. package/apps/hello-world/eslint.config.mjs +25 -0
  13. package/apps/hello-world/favicon.ico +0 -0
  14. package/apps/hello-world/index.html +17 -0
  15. package/apps/hello-world/package.json +65 -0
  16. package/apps/hello-world/src/hello-world.html +6 -0
  17. package/apps/hello-world/src/hello-world.ts +17 -0
  18. package/apps/hello-world/src/main.ts +6 -0
  19. package/apps/hello-world/src/my-app.html +1 -0
  20. package/apps/hello-world/src/my-app.ts +3 -0
  21. package/apps/hello-world/src/resource.d.ts +15 -0
  22. package/apps/hello-world/src/stories/hello-world.stories.ts +53 -0
  23. package/apps/hello-world/test/my-app.spec.ts +15 -0
  24. package/apps/hello-world/test/setup.ts +29 -0
  25. package/apps/hello-world/tsconfig.json +18 -0
  26. package/apps/hello-world/tsconfig.vitest.json +11 -0
  27. package/apps/hello-world/vite.config.ts +19 -0
  28. package/apps/hello-world/vitest.config.ts +15 -0
  29. package/apps/hello-world-webpack/.env.development +0 -0
  30. package/apps/hello-world-webpack/.storybook/main.ts +18 -0
  31. package/apps/hello-world-webpack/.storybook/preview.ts +3 -0
  32. package/apps/hello-world-webpack/.stylelintrc.json +5 -0
  33. package/apps/hello-world-webpack/.yarnrc.yml +2 -0
  34. package/apps/hello-world-webpack/README.md +29 -0
  35. package/apps/hello-world-webpack/eslint.config.mjs +25 -0
  36. package/apps/hello-world-webpack/favicon.ico +0 -0
  37. package/apps/hello-world-webpack/index.html +15 -0
  38. package/apps/hello-world-webpack/package-lock.json +10178 -0
  39. package/apps/hello-world-webpack/package.json +55 -0
  40. package/apps/hello-world-webpack/src/main.ts +6 -0
  41. package/apps/hello-world-webpack/src/my-app.css +3 -0
  42. package/apps/hello-world-webpack/src/my-app.html +1 -0
  43. package/apps/hello-world-webpack/src/my-app.stories.ts +12 -0
  44. package/apps/hello-world-webpack/src/my-app.ts +3 -0
  45. package/apps/hello-world-webpack/src/resource.d.ts +13 -0
  46. package/apps/hello-world-webpack/tsconfig.json +18 -0
  47. package/apps/hello-world-webpack/webpack.config.js +111 -0
  48. package/dist/index.js.map +1 -1
  49. package/dist/index.mjs.map +1 -1
  50. package/dist/preset.js +35 -1
  51. package/dist/preset.js.map +1 -1
  52. package/dist/preset.mjs +34 -2
  53. package/dist/preset.mjs.map +1 -1
  54. package/dist/preview/render.js.map +1 -1
  55. package/dist/preview/render.mjs.map +1 -1
  56. package/dist/preview.js +75 -0
  57. package/dist/preview.js.map +1 -0
  58. package/dist/preview.mjs +73 -0
  59. package/dist/preview.mjs.map +1 -0
  60. package/dist/webpack.js +23 -0
  61. package/dist/webpack.js.map +1 -0
  62. package/dist/webpack.mjs +21 -0
  63. package/dist/webpack.mjs.map +1 -0
  64. package/jest.config.js +1 -1
  65. package/package.json +26 -23
  66. package/src/preset.ts +22 -5
  67. package/src/preview.ts +50 -0
  68. package/src/webpack.ts +21 -0
  69. package/__tests__/render.test.d.ts +0 -1
  70. package/dist/index.d.ts +0 -3
  71. package/dist/preset.d.ts +0 -8
  72. package/dist/preview/render.d.ts +0 -17
  73. package/dist/preview/types.d.ts +0 -5
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Dwayne Charrington
3
+ Copyright (c) 2025 aurelia
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # @aurelia/storybook
2
2
 
3
- > **Note:** Storybook support is currently in an early stage, and there may be bugs, issues, or unsupported features in this plugin. The intention is to make this plugin more production-ready when Aurelia 2 reaches stable release. Currently, it only works with Vite, with Webpack support planned shortly.
3
+ > **Note:** Storybook support is currently in an early stage, and there may be bugs, issues, or unsupported features in this plugin. The intention is to make this plugin more production-ready when Aurelia 2 reaches stable release.
4
4
 
5
- This package provides an integration between Aurelia 2 and Storybook 8 using Vite. It lets you write and render Aurelia 2 components as Storybook stories with full support for Storybook controls, actions, and interactive testing.
5
+ This package provides an integration between Aurelia 2 and Storybook 8 using Vite or Webpack. It lets you write and render Aurelia 2 components as Storybook stories with full support for Storybook controls, actions, and interactive testing.
6
6
 
7
7
  ## Features
8
8
 
9
- - **Vite-Powered Build**: Uses Vite (via the provided preset) to bundle your stories.
9
+ - **Vite & Webpack Support**: Works with both Vite (via `@storybook/builder-vite`) and Webpack 5 (via `@storybook/builder-webpack5`).
10
10
  - **Aurelia Enhancement**: Renders Aurelia 2 components using Aurelia's `enhance()` API.
11
11
  - **Storybook 8 Compatibility**: Fully compatible with Storybook 8's new rendering API.
12
12
  - **Arg & Action Support**: Use story args and actions as you would with any Storybook story.
@@ -87,6 +87,34 @@ To integrate Aurelia 2 with your Storybook instance, follow these steps:
87
87
 
88
88
  > **Note:** Addons such as `@storybook/addon-links`, `@storybook/addon-essentials`, and `@storybook/addon-interactions` are supported by installing them and adding them to the `addons` array in your configuration.
89
89
 
90
+ ### Using with Webpack
91
+
92
+ If you prefer to use Webpack instead of Vite, update your `.storybook/main.ts` configuration:
93
+
94
+ ```typescript
95
+ import type { StorybookConfig } from '@storybook/core-common';
96
+
97
+ const config: StorybookConfig = {
98
+ stories: ['../src/**/*.stories.@(ts|tsx|js|jsx|mdx)'],
99
+ addons: [
100
+ '@storybook/addon-webpack5-compiler-swc',
101
+ '@storybook/addon-links',
102
+ '@storybook/addon-essentials'
103
+ ],
104
+ framework: {
105
+ name: '@aurelia/storybook',
106
+ options: {},
107
+ },
108
+ core: {
109
+ builder: '@storybook/builder-webpack5',
110
+ },
111
+ };
112
+
113
+ export default config;
114
+ ```
115
+
116
+ The `.storybook/preview.ts` file remains the same for both Vite and Webpack configurations.
117
+
90
118
  3. **Add scripts to your package.json**:
91
119
  Add the following scripts to your `package.json` file to work with Storybook:
92
120
 
@@ -0,0 +1,49 @@
1
+ import { webpackFinal, viteFinal } from '../src/preset';
2
+ import { getRules } from '../src/webpack';
3
+
4
+ jest.mock('../src/webpack', () => ({
5
+ getRules: jest.fn(() => [
6
+ { test: /\.ts$/, use: 'ts-loader' },
7
+ { test: /\.html$/, use: 'html-loader' },
8
+ ]),
9
+ }));
10
+
11
+ describe('preset', () => {
12
+ describe('webpackFinal', () => {
13
+ it('should add rules to the webpack config', async () => {
14
+ const config = {
15
+ module: {
16
+ rules: [],
17
+ },
18
+ };
19
+ const result = await webpackFinal(config);
20
+ expect(result.module.rules).toEqual(getRules());
21
+ expect(getRules).toHaveBeenCalled();
22
+ });
23
+
24
+ it('should handle a config with no module.rules', async () => {
25
+ const config = {};
26
+ const result = await webpackFinal(config);
27
+ expect(result).toEqual(config);
28
+ });
29
+
30
+ it('should handle a config with existing rules', async () => {
31
+ const existingRule = { test: /\.js$/, use: 'babel-loader' };
32
+ const config = {
33
+ module: {
34
+ rules: [existingRule],
35
+ },
36
+ };
37
+ const result = await webpackFinal(config);
38
+ expect(result.module.rules).toEqual([existingRule, ...getRules()]);
39
+ });
40
+ });
41
+
42
+ describe('viteFinal', () => {
43
+ it('should return the config unchanged', async () => {
44
+ const config = { some: 'property' };
45
+ const result = await viteFinal(config);
46
+ expect(result).toBe(config);
47
+ });
48
+ });
49
+ });
@@ -0,0 +1,139 @@
1
+ import { render } from '../src/preview';
2
+ import * as renderUtils from '../src/preview/render';
3
+
4
+ jest.mock('../src/preview/render', () => ({
5
+ ...jest.requireActual('../src/preview/render'),
6
+ bootstrapAureliaApp: jest.fn(),
7
+ }));
8
+
9
+ describe('preview', () => {
10
+ let bootstrapAureliaAppSpy: jest.SpyInstance;
11
+ let fakeAureliaApp: { start: jest.Mock; stop: jest.Mock };
12
+
13
+ beforeEach(() => {
14
+ bootstrapAureliaAppSpy = jest.spyOn(renderUtils, 'bootstrapAureliaApp');
15
+ fakeAureliaApp = {
16
+ start: jest.fn().mockResolvedValue(undefined),
17
+ stop: jest.fn().mockResolvedValue(undefined),
18
+ };
19
+ bootstrapAureliaAppSpy.mockReturnValue(fakeAureliaApp);
20
+ document.body.innerHTML = '';
21
+ });
22
+
23
+ afterEach(() => {
24
+ jest.clearAllMocks();
25
+ });
26
+
27
+ it('should return a container element', () => {
28
+ const context = {
29
+ storyFn: () => ({ Component: class {} }),
30
+ component: class {},
31
+ };
32
+ const container = render({}, context);
33
+ expect(container).toBeInstanceOf(HTMLElement);
34
+ expect(container.tagName).toBe('DIV');
35
+ });
36
+
37
+ it('should call storyFn', () => {
38
+ const storyFn = jest.fn(() => ({ Component: class {} }));
39
+ const context = {
40
+ storyFn,
41
+ component: class {},
42
+ };
43
+ render({}, context);
44
+ expect(storyFn).toHaveBeenCalledTimes(1);
45
+ });
46
+
47
+ it('should not bootstrap Aurelia if story has no Component or template', () => {
48
+ const context = {
49
+ storyFn: () => ({}),
50
+ component: class {},
51
+ };
52
+ render({}, context);
53
+ expect(bootstrapAureliaAppSpy).not.toHaveBeenCalled();
54
+ });
55
+
56
+ it('should bootstrap Aurelia if story has a Component', () => {
57
+ const DummyComponent = class {};
58
+ const context = {
59
+ storyFn: () => ({ Component: DummyComponent }),
60
+ component: class {},
61
+ };
62
+ const args = { a: 1 };
63
+ const container = render(args, context);
64
+ expect(bootstrapAureliaAppSpy).toHaveBeenCalledWith(
65
+ { Component: DummyComponent },
66
+ args,
67
+ container,
68
+ DummyComponent
69
+ );
70
+ expect(fakeAureliaApp.start).toHaveBeenCalled();
71
+ });
72
+
73
+ it('should bootstrap Aurelia if story has a template', () => {
74
+ const template = '<div></div>';
75
+ const context = {
76
+ storyFn: () => ({ template }),
77
+ component: class {},
78
+ };
79
+ const args = { a: 1 };
80
+ const container = render(args, context);
81
+ expect(bootstrapAureliaAppSpy).toHaveBeenCalledWith(
82
+ { template },
83
+ args,
84
+ container,
85
+ context.component
86
+ );
87
+ expect(fakeAureliaApp.start).toHaveBeenCalled();
88
+ });
89
+
90
+ it('should call cleanup for the previous story', () => {
91
+ const storyFn1 = () => ({ Component: class {} });
92
+ const storyFn2 = () => ({ template: 'hello' });
93
+
94
+ // First render
95
+ render({}, { storyFn: storyFn1, component: class {} });
96
+
97
+ // Second render
98
+ render({}, { storyFn: storyFn2, component: class {} });
99
+
100
+ expect(fakeAureliaApp.stop).toHaveBeenCalledTimes(1);
101
+ });
102
+
103
+ it('should handle Aurelia start failure', async () => {
104
+ const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
105
+ const error = new Error('Failed to start');
106
+ fakeAureliaApp.start.mockRejectedValue(error);
107
+
108
+ const context = {
109
+ storyFn: () => ({ Component: class {} }),
110
+ component: class {},
111
+ };
112
+
113
+ render({}, context);
114
+
115
+ // allow microtasks to run
116
+ await new Promise(resolve => setTimeout(resolve, 0));
117
+
118
+ expect(consoleErrorSpy).toHaveBeenCalledWith('Failed to start Aurelia app:', error);
119
+ consoleErrorSpy.mockRestore();
120
+ });
121
+
122
+ it('should handle Aurelia stop failure', async () => {
123
+ const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
124
+ const error = new Error('Failed to stop');
125
+ fakeAureliaApp.stop.mockRejectedValue(error);
126
+
127
+ // First render
128
+ render({}, { storyFn: () => ({ Component: class {} }), component: class {} });
129
+
130
+ // Second render to trigger cleanup
131
+ render({}, { storyFn: () => ({ Component: class {} }), component: class {} });
132
+
133
+ // allow microtasks to run
134
+ await new Promise(resolve => setTimeout(resolve, 0));
135
+
136
+ expect(consoleErrorSpy).toHaveBeenCalledWith('Failed to stop Aurelia app:', error);
137
+ consoleErrorSpy.mockRestore();
138
+ });
139
+ });
@@ -1,5 +1,4 @@
1
1
  import { STORY_CHANGED } from '@storybook/core-events';
2
- import { CustomElement } from 'aurelia';
3
2
  import {
4
3
  render,
5
4
  renderToCanvas,
@@ -0,0 +1,21 @@
1
+ import { getRules } from '../src/webpack';
2
+
3
+ describe('webpack', () => {
4
+ describe('getRules', () => {
5
+ it('should return the correct rules', () => {
6
+ const rules = getRules();
7
+ expect(rules).toEqual([
8
+ {
9
+ test: /\.ts$/i,
10
+ use: ['ts-loader', '@aurelia/webpack-loader'],
11
+ exclude: /node_modules/,
12
+ },
13
+ {
14
+ test: /\.html$/i,
15
+ use: '@aurelia/webpack-loader',
16
+ exclude: /node_modules/,
17
+ },
18
+ ]);
19
+ });
20
+ });
21
+ });
@@ -0,0 +1,30 @@
1
+ import type { StorybookConfig } from '@storybook/core-common';
2
+ import { mergeConfig } from 'vite';
3
+
4
+ const config: StorybookConfig & { viteFinal?: (config: any, options: any) => any } = {
5
+ stories: ['../src/stories/**/*.stories.@(ts|tsx|js|jsx|mdx)'],
6
+ addons: [
7
+ '@storybook/addon-links',
8
+ '@storybook/addon-essentials',
9
+ '@storybook/addon-interactions'
10
+ ],
11
+ framework: {
12
+ name: '@aurelia/storybook',
13
+ options: {},
14
+ },
15
+ core: {
16
+ builder: '@storybook/builder-vite',
17
+ },
18
+ viteFinal: async (viteConfig) => {
19
+ viteConfig.optimizeDeps = viteConfig.optimizeDeps || {};
20
+ viteConfig.optimizeDeps.exclude = viteConfig.optimizeDeps.exclude || [];
21
+ if (!viteConfig.optimizeDeps.exclude.includes('@aurelia/runtime-html')) {
22
+ viteConfig.optimizeDeps.exclude.push('@aurelia/runtime-html');
23
+ }
24
+ return mergeConfig(viteConfig, {
25
+ // ...any additional Vite configuration
26
+ });
27
+ },
28
+ };
29
+
30
+ export default config as any;
@@ -0,0 +1 @@
1
+ export { render, renderToCanvas } from '@aurelia/storybook';
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": [
3
+ "stylelint-config-standard"
4
+ ]
5
+ }
@@ -0,0 +1,2 @@
1
+ # For compatibility in yarn 2+
2
+ nodeLinker: node-modules
@@ -0,0 +1,28 @@
1
+ # Aurelia Storybook Hello World
2
+
3
+ This project is bootstrapped by [aurelia/new](https://github.com/aurelia/new).
4
+
5
+ ## Start dev web server
6
+
7
+ npm start
8
+
9
+ ## Start Storybook
10
+
11
+ npm run storybook
12
+
13
+ ## Build the app in production mode
14
+
15
+ npm run build
16
+
17
+ ## Build Storybook
18
+
19
+ npm run build-storybook
20
+
21
+ ## Unit Tests
22
+
23
+ npm run test
24
+
25
+ Run unit tests in watch mode.
26
+
27
+ npm run test:watch
28
+
@@ -0,0 +1,25 @@
1
+ import eslint from "@eslint/js";
2
+ import tseslint from 'typescript-eslint';
3
+ import tsParser from "@typescript-eslint/parser";
4
+ import globals from "globals";
5
+
6
+ export default [
7
+ eslint.configs.recommended,
8
+ ...tseslint.configs.recommended,
9
+ {
10
+ files: ["**/*.ts"],
11
+
12
+ languageOptions: {
13
+ globals: {
14
+ ...globals.builtin,
15
+ ...globals.nodeBuiltin,
16
+ ...globals.browser,
17
+ ...globals.node,
18
+ },
19
+
20
+ parser: tsParser,
21
+ ecmaVersion: 2019,
22
+ sourceType: "module",
23
+ },
24
+ }
25
+ ];
Binary file
@@ -0,0 +1,17 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+
4
+ <head>
5
+ <meta charset="utf-8">
6
+ <title>Aurelia</title>
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ <script type="module" src="/src/main.ts"></script>
9
+ <base href="/">
10
+ </head>
11
+
12
+ <body>
13
+ <my-app></my-app>
14
+ </body>
15
+
16
+ </html>
17
+
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "apptasks-video",
3
+ "description": "An Aurelia 2 client application.",
4
+ "version": "0.1.0",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "???"
8
+ },
9
+ "license": "UNLICENSED",
10
+ "dependencies": {
11
+ "@aurelia/router": "^2.0.0-beta.24",
12
+ "@aurelia/validation": "^2.0.0-beta.24",
13
+ "@aurelia/validation-html": "^2.0.0-beta.24",
14
+ "aurelia": "^2.0.0-beta.24"
15
+ },
16
+ "devDependencies": {
17
+ "@aurelia/storybook": "^0.1.1",
18
+ "@aurelia/testing": "^2.0.0-beta.24",
19
+ "@aurelia/vite-plugin": "^2.0.0-beta.24",
20
+ "@storybook/addon-actions": "^8.5.3",
21
+ "@storybook/addon-essentials": "^8.5.3",
22
+ "@storybook/addon-interactions": "^8.5.3",
23
+ "@storybook/addon-links": "^8.5.3",
24
+ "@storybook/builder-vite": "^8.5.3",
25
+ "@storybook/core-common": "^8.5.3",
26
+ "@storybook/preview-api": "^8.5.3",
27
+ "@storybook/testing-library": "^0.2.1",
28
+ "@storybook/types": "^8.5.3",
29
+ "@tailwindcss/vite": "^4.0.0",
30
+ "@types/node": "^22.10.2",
31
+ "eslint": "^9.17.0",
32
+ "globals": "^15.14.0",
33
+ "jsdom": "^25.0.1",
34
+ "node-html-parser": "^7.0.1",
35
+ "sass": "^1.83.4",
36
+ "stylelint": "^16.12.0",
37
+ "stylelint-config-standard": "^36.0.1",
38
+ "stylus": "^0.64.0",
39
+ "tailwindcss": "^4.0.0",
40
+ "tslib": "^2.8.1",
41
+ "typescript": "^5.7.2",
42
+ "typescript-eslint": "^8.18.1",
43
+ "vite": "^6.0.3",
44
+ "vite-plugin-node-polyfills": "^0.22.0",
45
+ "vitest": "^2.1.8"
46
+ },
47
+ "scripts": {
48
+ "lint:js": "eslint src test",
49
+ "lint:css": "stylelint \"src/**/*.css\"",
50
+ "lint": "npm run lint:js && npm run lint:css",
51
+ "pretest": "npm run lint",
52
+ "start": "vite",
53
+ "build": "vite build",
54
+ "test": "vitest",
55
+ "storybook": "storybook dev -p 6006",
56
+ "build-storybook": "storybook build"
57
+ },
58
+ "type": "module",
59
+ "overrides": {
60
+ "vite-plugin-node-polyfills": {
61
+ "vite": "^6.0.0"
62
+ }
63
+ },
64
+ "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
65
+ }
@@ -0,0 +1,6 @@
1
+ <div style="border: 1px solid #ccc; padding: 16px; border-radius: 4px;">
2
+ <h1>${message}</h1>
3
+ <p>Counter: ${counter}</p>
4
+ <button click.trigger="increment()">Increment</button>
5
+ <au-slot></au-slot>
6
+ </div>
@@ -0,0 +1,17 @@
1
+ import { bindable } from 'aurelia';
2
+
3
+ export class HelloWorld {
4
+ @bindable() message = 'Hello from Aurelia!';
5
+ // New reactive counter property to track number of clicks
6
+ counter = 0;
7
+ // New bindable event callback for the increment action
8
+ @bindable() onIncrement;
9
+
10
+ // Method to increment the counter and fire the onIncrement callback if provided.
11
+ increment() {
12
+ this.counter++;
13
+ if (this.onIncrement) {
14
+ this.onIncrement(this.counter);
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,6 @@
1
+ import Aurelia from 'aurelia';
2
+ import { MyApp } from './my-app';
3
+
4
+ Aurelia
5
+ .app(MyApp)
6
+ .start();
@@ -0,0 +1 @@
1
+ <h1>Hello World</h1>
@@ -0,0 +1,3 @@
1
+ export class MyApp {
2
+ // Your app logic
3
+ }
@@ -0,0 +1,15 @@
1
+ declare module '*.html' {
2
+ import { IContainer, PartialBindableDefinition } from 'aurelia';
3
+ export const name: string;
4
+ export const template: string;
5
+ export default template;
6
+ export const dependencies: string[];
7
+ export const containerless: boolean | undefined;
8
+ export const bindables: Record<string, PartialBindableDefinition>;
9
+ export const shadowOptions: { mode: 'open' | 'closed' } | undefined;
10
+ export function register(container: IContainer): void;
11
+ }
12
+
13
+ declare module '*.css';
14
+
15
+ declare module '*.au';
@@ -0,0 +1,53 @@
1
+ import { HelloWorld } from '../hello-world';
2
+ import { action } from '@storybook/addon-actions';
3
+ import { userEvent, within } from '@storybook/testing-library';
4
+
5
+ const meta = {
6
+ title: 'Example/HelloWorld',
7
+ component: HelloWorld,
8
+ render: (args) => ({
9
+ template: `<hello-world message.bind="message" on-increment.bind="onIncrement"></hello-world>`,
10
+ }),
11
+ argTypes: {
12
+ message: { control: 'text' },
13
+ onIncrement: { action: 'increment' }
14
+ }
15
+ };
16
+
17
+ export default meta;
18
+
19
+ export const DefaultHelloWorld = {
20
+ args: {
21
+ message: "Hello from Storybook!",
22
+ onIncrement: action('increment')
23
+ }
24
+ };
25
+
26
+ export const InteractiveHelloWorld = {
27
+ args: {
28
+ message: "Try clicking the button!",
29
+ onIncrement: action('increment')
30
+ },
31
+ play: async ({ canvasElement }) => {
32
+ const canvas = within(canvasElement);
33
+ const button = canvas.getByRole('button');
34
+ await userEvent.click(button);
35
+ await userEvent.click(button);
36
+ await userEvent.click(button);
37
+ }
38
+ };
39
+
40
+ export const NoArgs = {
41
+ render: () => ({
42
+ template: `<hello-world></hello-world>`
43
+ })
44
+ };
45
+
46
+ export const WithCustomTemplate = {
47
+ render: (args) => ({
48
+ template: `<hello-world message.bind="message">Click me!</hello-world>`
49
+ }),
50
+ args: {
51
+ message: "This is a custom message"
52
+ }
53
+ };
@@ -0,0 +1,15 @@
1
+ import { describe, it } from 'vitest';
2
+ import { MyApp } from '../src/my-app';
3
+ import { createFixture } from '@aurelia/testing';
4
+
5
+ describe('my-app', () => {
6
+ it('should render message', async () => {
7
+ const { assertText } = await createFixture(
8
+ '<my-app></my-app>',
9
+ {},
10
+ [MyApp],
11
+ ).started;
12
+
13
+ assertText('Hello World!', { compact: true });
14
+ });
15
+ });
@@ -0,0 +1,29 @@
1
+ import { BrowserPlatform } from '@aurelia/platform-browser';
2
+ import { setPlatform, onFixtureCreated, type IFixture } from '@aurelia/testing';
3
+ import { beforeAll, afterEach } from 'vitest';
4
+
5
+ // Sets up the Aurelia environment for testing
6
+ function bootstrapTextEnv() {
7
+ const platform = new BrowserPlatform(window);
8
+ setPlatform(platform);
9
+ BrowserPlatform.set(globalThis, platform);
10
+ }
11
+
12
+ const fixtures: IFixture<object>[] = [];
13
+ beforeAll(() => {
14
+ bootstrapTextEnv();
15
+ onFixtureCreated(fixture => {
16
+ fixtures.push(fixture);
17
+ });
18
+ });
19
+
20
+ afterEach(() => {
21
+ fixtures.forEach(async f => {
22
+ try {
23
+ await f.stop(true);
24
+ } catch {
25
+ // ignore
26
+ }
27
+ });
28
+ fixtures.length = 0;
29
+ });
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "esnext",
4
+ "moduleResolution": "node",
5
+ "skipLibCheck": true,
6
+ "target": "ES2017",
7
+ "esModuleInterop": true,
8
+ "resolveJsonModule": true,
9
+ "importHelpers": true,
10
+ "sourceMap": true
11
+ },
12
+ "include": [
13
+ "src"
14
+ , "aurelia-sfc-plugin.js" ],
15
+ "files": [
16
+ "src/resource.d.ts"
17
+ ]
18
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "composite": true,
5
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.vitest.tsbuildinfo",
6
+ "types": [
7
+ "node",
8
+ "jsdom"
9
+ ]
10
+ }
11
+ }
@@ -0,0 +1,19 @@
1
+ import { defineConfig } from 'vite';
2
+ import { nodePolyfills } from 'vite-plugin-node-polyfills'
3
+ import aurelia from '@aurelia/vite-plugin';
4
+
5
+ export default defineConfig({
6
+ server: {
7
+ open: !process.env.CI,
8
+ port: 9000,
9
+ },
10
+ esbuild: {
11
+ target: 'es2022'
12
+ },
13
+ plugins: [
14
+ aurelia({
15
+ useDev: true,
16
+ }),
17
+ nodePolyfills(),
18
+ ],
19
+ });