@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
@@ -1,139 +1,17 @@
1
- import { render } from '../src/preview';
1
+ import { defineAureliaStory, render, renderToCanvas } from '../src/preview';
2
2
  import * as renderUtils from '../src/preview/render';
3
3
 
4
- jest.mock('../src/preview/render', () => ({
5
- ...jest.requireActual('../src/preview/render'),
6
- bootstrapAureliaApp: jest.fn(),
7
- }));
8
-
9
4
  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');
5
+ it('re-exports render', () => {
6
+ expect(render).toBe(renderUtils.render);
35
7
  });
36
8
 
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();
9
+ it('re-exports renderToCanvas', () => {
10
+ expect(renderToCanvas).toBe(renderUtils.renderToCanvas);
120
11
  });
121
12
 
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();
13
+ it('returns the provided story result from defineAureliaStory', () => {
14
+ const story = { template: '<div></div>' };
15
+ expect(defineAureliaStory(story)).toBe(story);
138
16
  });
139
- });
17
+ });
@@ -1,8 +1,7 @@
1
- import { STORY_CHANGED } from 'storybook/internal/core-events';
2
1
  import {
3
2
  render,
4
3
  renderToCanvas,
5
- bootstrapAureliaApp,
4
+ createAureliaApp,
6
5
  createComponentTemplate,
7
6
  } from '../src/preview/render';
8
7
 
@@ -24,9 +23,12 @@ jest.mock('aurelia', () => {
24
23
  describe('render', () => {
25
24
  it('throws an error when no component is provided', () => {
26
25
  expect(() =>
27
- render({}, { id: 'story-1', component: undefined as any } as any)
28
- ).toThrowError(
29
- 'Unable to render story story-1 as the component annotation is missing from the default export'
26
+ render(
27
+ {},
28
+ { id: 'story-1', title: 'Test', name: 'Story', component: undefined as any } as any
29
+ )
30
+ ).toThrow(
31
+ 'Unable to render story Test / Story as the component annotation is missing from the default export'
30
32
  );
31
33
  });
32
34
 
@@ -34,18 +36,16 @@ describe('render', () => {
34
36
  const DummyComponent = () => {};
35
37
  const args = { foo: 'bar' };
36
38
  const result = render(args, { id: 'story-1', component: DummyComponent as any } as any);
37
- expect(result).toEqual({ Component: DummyComponent, props: args, template: '' });
39
+ expect(result).toEqual({ Component: DummyComponent, props: args });
38
40
  });
39
41
  });
40
42
 
41
43
  describe('renderToCanvas', () => {
42
44
  let canvas: HTMLElement;
43
- let dummyChannel: { on: jest.Mock; off: jest.Mock };
44
45
  const DummyComponent = class {};
45
46
 
46
47
  beforeEach(() => {
47
48
  canvas = document.createElement('div');
48
- dummyChannel = { on: jest.fn(), off: jest.fn() } as any;
49
49
  });
50
50
 
51
51
  it('calls showError when the story function returns a falsy value', async () => {
@@ -62,8 +62,6 @@ describe('renderToCanvas', () => {
62
62
  parameters: {},
63
63
  component: DummyComponent as any,
64
64
  args: {},
65
- viewMode: 'story',
66
- channel: dummyChannel,
67
65
  },
68
66
  forceRemount: false,
69
67
  } as any;
@@ -84,9 +82,8 @@ describe('renderToCanvas', () => {
84
82
  const showError = jest.fn() as any;
85
83
  const showMain = jest.fn() as any;
86
84
 
87
- // Spy on bootstrapAureliaApp to simulate app creation.
88
85
  const bootstrapSpy = jest
89
- .spyOn(require('../src/preview/render'), 'bootstrapAureliaApp')
86
+ .spyOn(require('../src/preview/render'), 'createAureliaApp')
90
87
  .mockReturnValue(fakeAurelia);
91
88
 
92
89
  const context = {
@@ -99,23 +96,17 @@ describe('renderToCanvas', () => {
99
96
  parameters: { args: { param: 'foo' } },
100
97
  component: DummyComponent as any,
101
98
  args: { test: 'bar' },
102
- viewMode: 'story',
103
- channel: dummyChannel,
104
99
  },
105
100
  forceRemount: false,
106
101
  } as any;
107
102
 
108
- const cleanup = await renderToCanvas(context, canvas, bootstrapAureliaApp);
103
+ const cleanup = await renderToCanvas(context, canvas, createAureliaApp);
109
104
  expect(showError).not.toHaveBeenCalled();
110
105
  expect(showMain).toHaveBeenCalled();
111
106
  expect(bootstrapSpy).toHaveBeenCalled();
112
107
 
113
- // Simulate cleanup (which should remove the STORY_CHANGED listener)
114
108
  await cleanup();
115
- expect(dummyChannel.off).toHaveBeenCalledWith(
116
- STORY_CHANGED,
117
- expect.any(Function)
118
- );
109
+ expect(fakeAurelia.stop).toHaveBeenCalled();
119
110
  bootstrapSpy.mockRestore();
120
111
  });
121
112
 
@@ -134,7 +125,7 @@ describe('renderToCanvas', () => {
134
125
  const showMain = jest.fn() as any;
135
126
 
136
127
  const bootstrapSpy = jest
137
- .spyOn(require('../src/preview/render'), 'bootstrapAureliaApp')
128
+ .spyOn(require('../src/preview/render'), 'createAureliaApp')
138
129
  .mockReturnValue(fakeAurelia);
139
130
 
140
131
  // First render: bootstrap the app.
@@ -148,12 +139,10 @@ describe('renderToCanvas', () => {
148
139
  parameters: { args: { param: 'foo' } },
149
140
  component: DummyComponent as any,
150
141
  args: { test: 'bar' },
151
- viewMode: 'story',
152
- channel: dummyChannel,
153
142
  },
154
143
  forceRemount: false,
155
144
  } as any;
156
- await renderToCanvas(context, canvas, bootstrapAureliaApp);
145
+ await renderToCanvas(context, canvas, createAureliaApp);
157
146
  expect(bootstrapSpy).toHaveBeenCalledTimes(1);
158
147
 
159
148
  // Second render with new args; should update viewModel instead of re-bootstrap.
@@ -167,9 +156,9 @@ describe('renderToCanvas', () => {
167
156
  args: { test: 'qux' },
168
157
  },
169
158
  } as any;
170
- await renderToCanvas(newContext, canvas, bootstrapAureliaApp);
159
+ await renderToCanvas(newContext, canvas, createAureliaApp);
171
160
  expect(bootstrapSpy).toHaveBeenCalledTimes(1);
172
- expect(fakeViewModel).toEqual({ param: 'baz', test: 'qux' });
161
+ expect(fakeViewModel).toEqual({ param: 'baz', test: 'updated' });
173
162
  bootstrapSpy.mockRestore();
174
163
  });
175
164
  });