├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── release.yml
├── .gitignore
├── .prettierignore
├── .vscode
└── settings.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── example
├── .browserslistrc
├── .editorconfig
├── .gitignore
├── .storybook
│ ├── main.ts
│ ├── preview.ts
│ ├── tsconfig.json
│ └── typings.d.ts
├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ └── tasks.json
├── README.md
├── angular.json
├── documentation.json
├── karma.conf.js
├── package.json
├── src
│ ├── app
│ │ ├── app.component.html
│ │ ├── app.component.scss
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ ├── ngrx
│ │ │ ├── counter.actions.ts
│ │ │ ├── counter.reducer.ts
│ │ │ ├── my-counter.component.html
│ │ │ ├── my-counter.component.ts
│ │ │ ├── my-counter.spec.ts
│ │ │ └── my-counter.stories.ts
│ │ └── signal
│ │ │ ├── with-signal-input.component.ts
│ │ │ ├── with-signal-input.spec.ts
│ │ │ └── with-signal-input.stories.ts
│ ├── assets
│ │ └── .gitkeep
│ ├── environments
│ │ ├── environment.prod.ts
│ │ └── environment.ts
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ ├── polyfills.ts
│ ├── stories
│ │ ├── .eslintrc.json
│ │ ├── Button.stories.ts
│ │ ├── Header.stories.ts
│ │ ├── Introduction.mdx
│ │ ├── Page.stories.ts
│ │ ├── User.ts
│ │ ├── assets
│ │ │ ├── code-brackets.svg
│ │ │ ├── colors.svg
│ │ │ ├── comments.svg
│ │ │ ├── direction.svg
│ │ │ ├── flow.svg
│ │ │ ├── plugin.svg
│ │ │ ├── repo.svg
│ │ │ └── stackalt.svg
│ │ ├── button.component.ts
│ │ ├── button.css
│ │ ├── button.spec.ts
│ │ ├── header.component.ts
│ │ ├── header.css
│ │ ├── page.component.ts
│ │ └── page.css
│ ├── styles.scss
│ └── test.ts
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.spec.json
└── yarn.lock
├── package.json
├── src
└── index.ts
├── tsconfig.json
└── yarn.lock
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Additional context**
27 | Add any other context about the problem here.
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Issue:
2 |
3 | ## What Changed
4 |
5 |
6 |
7 | ## Checklist
8 |
9 | Check the ones applicable to your change:
10 |
11 | - [ ] Tests are updated
12 | - [ ] Documentation is updated
13 |
14 | ## Change Type
15 |
16 | Indicate the type of change your pull request is:
17 |
18 | - [ ] `documentation`
19 | - [ ] `patch`
20 | - [ ] `minor`
21 | - [ ] `major`
22 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on: [push]
4 |
5 | jobs:
6 | release:
7 | runs-on: ubuntu-latest
8 | if: "!contains(github.event.head_commit.message, 'ci skip') && !contains(github.event.head_commit.message, 'skip ci')"
9 | steps:
10 | - uses: actions/checkout@v2
11 |
12 | - name: Prepare repository
13 | run: git fetch --unshallow --tags
14 |
15 | - name: Use Node.js 18.19.x
16 | uses: actions/setup-node@v1
17 | with:
18 | node-version: 18.19.x
19 |
20 | - name: Install dependencies
21 | uses: bahmutov/npm-install@v1
22 |
23 | - name: Create Release
24 | env:
25 | GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
26 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
27 | run: |
28 | yarn release
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | .DS_Store
3 | dist
4 |
5 | node_modules
6 | example/node_modules
7 |
8 | .env
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | dist
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "prettier.bracketSpacing": true,
4 | "prettier.semi": false,
5 | "prettier.singleQuote": true,
6 | "prettier.trailingComma": "all",
7 | "prettier.tabWidth": 2,
8 | "prettier.printWidth": 100,
9 | "editor.formatOnSave": true,
10 | "editor.tabSize": 2,
11 | "deepscan.enable": true,
12 | "typescript.tsdk": "node_modules\\typescript\\lib"
13 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # v1.0.3 (Tue Jul 09 2024)
2 |
3 | #### ⚠️ Pushed to `main`
4 |
5 | - Merge branch 'next' ([@Marklb](https://github.com/Marklb))
6 | - Update SB version in Readme ([@Marklb](https://github.com/Marklb))
7 | - Fix composeStories types and example snippets ([@Marklb](https://github.com/Marklb))
8 | - Upgrade dependencies ([@Marklb](https://github.com/Marklb))
9 | - Update workflow node version ([@Marklb](https://github.com/Marklb))
10 | - Upgrade to Storybook v8 ([@Marklb](https://github.com/Marklb))
11 | - Upgrade example to Angular 18 ([@Marklb](https://github.com/Marklb))
12 | - Upgrade example to Angular 17 ([@Marklb](https://github.com/Marklb))
13 | - Before example upgrade ([@Marklb](https://github.com/Marklb))
14 |
15 | #### Authors: 1
16 |
17 | - Mark Berry ([@Marklb](https://github.com/Marklb))
18 |
19 | ---
20 |
21 | # v1.0.2 (Wed Nov 22 2023)
22 |
23 | #### ⚠️ Pushed to `main`
24 |
25 | - Merge branch 'next' into main ([@Marklb](https://github.com/Marklb))
26 | - Change example tests to createMountable ([@Marklb](https://github.com/Marklb))
27 | - Add `createMountable` and workaround for redundant component passing ([@Marklb](https://github.com/Marklb))
28 |
29 | #### Authors: 1
30 |
31 | - Mark Berry ([@Marklb](https://github.com/Marklb))
32 |
33 | ---
34 |
35 | # v0.0.13 (Wed Nov 22 2023)
36 |
37 | #### 🐛 Bug Fix
38 |
39 | - Use manual GH token [#4](https://github.com/storybookjs/testing-angular/pull/4) ([@shilman](https://github.com/shilman))
40 | - Upgrade release workflow to node@16 [#3](https://github.com/storybookjs/testing-angular/pull/3) ([@shilman](https://github.com/shilman))
41 |
42 | #### ⚠️ Pushed to `main`
43 |
44 | - Return `applicationConfig`, instead of adding providers to root component ([@Marklb](https://github.com/Marklb))
45 | - Merge remote-tracking branch 'origin/next' into next ([@Marklb](https://github.com/Marklb))
46 | - Remove unused files ([@Marklb](https://github.com/Marklb))
47 | - Refactor for Storybook v7 ([@Marklb](https://github.com/Marklb))
48 |
49 | #### Authors: 2
50 |
51 | - Mark Berry ([@Marklb](https://github.com/Marklb))
52 | - Michael Shilman ([@shilman](https://github.com/shilman))
53 |
54 | ---
55 |
56 | # v0.0.12 (Thu Nov 25 2021)
57 |
58 | #### ⚠️ Pushed to `main`
59 |
60 | - Fix first render check ([@Marklb](https://github.com/Marklb))
61 |
62 | #### Authors: 1
63 |
64 | - Mark Berry ([@Marklb](https://github.com/Marklb))
65 |
66 | ---
67 |
68 | # v0.0.10 (Thu Nov 25 2021)
69 |
70 | #### ⚠️ Pushed to `main`
71 |
72 | - Fix first render check ([@Marklb](https://github.com/Marklb))
73 |
74 | #### Authors: 1
75 |
76 | - Mark Berry ([@Marklb](https://github.com/Marklb))
77 |
78 | ---
79 |
80 | # v0.0.9 (Sat Sep 25 2021)
81 |
82 | #### ⚠️ Pushed to `main`
83 |
84 | - Fix typo and consistency in README ([@Marklb](https://github.com/Marklb))
85 |
86 | #### Authors: 1
87 |
88 | - Mark Berry ([@Marklb](https://github.com/Marklb))
89 |
90 | ---
91 |
92 | # v0.0.8 (Wed Sep 22 2021)
93 |
94 | #### ⚠️ Pushed to `main`
95 |
96 | - Bump version to v0.0.7 ([@Marklb](https://github.com/Marklb))
97 | - Rename to '@storybook/testing-angular' ([@Marklb](https://github.com/Marklb))
98 | - Add github files ([@Marklb](https://github.com/Marklb))
99 | - Bump version to v0.0.6 ([@Marklb](https://github.com/Marklb))
100 | - Update README from React to Angular ([@Marklb](https://github.com/Marklb))
101 | - Update code comments ([@Marklb](https://github.com/Marklb))
102 | - Call setGlobalConfig in example test setup ([@Marklb](https://github.com/Marklb))
103 | - Fix compiling of example ([@Marklb](https://github.com/Marklb))
104 | - Fix composeStory not adding component from Meta. ([@Marklb](https://github.com/Marklb))
105 | - Initial commit ([@Marklb](https://github.com/Marklb))
106 | - v0.0.2 ([@Marklb](https://github.com/Marklb))
107 |
108 | #### Authors: 1
109 |
110 | - Mark Berry ([@Marklb](https://github.com/Marklb))
111 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | MIT License
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Testing utilities that allow you to reuse your stories in your unit tests
6 |
7 |
8 |
9 | ## The problem
10 |
11 | You are using [Storybook](https://storybook.js.org/) for your components and writing tests for them with [Jasmine test framework](https://jasmine.github.io/) or [Angular testing library](https://testing-library.com/), most likely with [Karma test runner](https://karma-runner.github.io/). In your Storybook stories, you already defined the scenarios of your components. You also set up the necessary decorators (theming, routing, state management, etc.) to make them all render correctly. When you're writing tests, you also end up defining scenarios of your components, as well as setting up the necessary decorators. By doing the same thing twice, you feel like you're spending too much effort, making writing and maintaining stories/tests become less like fun and more like a burden.
12 |
13 | ## The solution
14 |
15 | `@storybook/testing-angular` is a solution to reuse your Storybook stories in your Angular tests. By reusing your stories in your tests, you have a catalog of component scenarios ready to be tested. All [args](https://storybook.js.org/docs/angular/writing-stories/args) and [decorators](https://storybook.js.org/docs/angular/writing-stories/decorators) from your [story](https://storybook.js.org/docs/angular/api/csf#named-story-exports) and its [meta](https://storybook.js.org/docs/angular/api/csf#default-export), and also [global decorators](https://storybook.js.org/docs/angular/writing-stories/decorators#global-decorators), will be composed by this library and returned to you in a simple component. This way, in your unit tests, all you have to do is select which story you want to render, and all the necessary setup will be already done for you. This is the missing piece that allows for better shareability and maintenance between writing tests and writing Storybook stories.
16 |
17 | ## Installation
18 |
19 | This library should be installed as one of your project's `devDependencies`:
20 |
21 | via [npm](https://www.npmjs.com/)
22 |
23 |
32 |
33 | ## Setup
34 |
35 | ### Storybook 8 and Component Story Format
36 |
37 | This library requires you to be using Storybook version 8, [Component Story Format (CSF)](https://storybook.js.org/docs/angular/api/csf) and [hoisted CSF annotations](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#hoisted-csf-annotations), which is the recommended way to write stories since Storybook 8.
38 |
39 | Essentially, if you use Storybook 8 and your stories look similar to this, you're good to go!
40 |
41 | ```ts
42 | // CSF: default export (meta) + named exports (stories)
43 | export default {
44 | title: 'Example/Button',
45 | component: Button,
46 | } as Meta;
47 |
48 | const Primary: Story = args => (args: ButtonComponent) => ({
49 | props: args,
50 | }); // or with Template.bind({})
51 | Primary.args = {
52 | primary: true,
53 | };
54 | ```
55 |
56 | ### Global config
57 |
58 | > This is an optional step. If you don't have [global decorators](https://storybook.js.org/docs/angular/writing-stories/decorators#global-decorators), there's no need to do this. However, if you do, this is a necessary step for your global decorators to be applied.
59 |
60 | If you have global decorators/parameters/etc and want them applied to your stories when testing them, you first need to set this up. You can do this by adding to test [setup file](https://angular.io/guide/testing#configuration):
61 |
62 | ```ts
63 | // test.ts <-- this will run before the tests in karma.
64 | import { setProjectAnnotations } from '@storybook/testing-angular';
65 | import * as globalStorybookConfig from '../.storybook/preview'; // path of your preview.js file
66 |
67 | setProjectAnnotations(globalStorybookConfig);
68 | ```
69 |
70 | ## Usage
71 |
72 | ### `composeStories`
73 |
74 | `composeStories` will process all stories from the component you specify, compose args/decorators in all of them and return an object containing the composed stories.
75 |
76 | If you use the composed story (e.g. PrimaryButton), the component will render with the args that are passed in the story. However, you are free to pass any props on top of the component, and those props will override the default values passed in the story's args.
77 |
78 | ```ts
79 | import { render, screen } from '@testing-library/angular';
80 | import {
81 | composeStories,
82 | createMountable,
83 | } from '@storybook/testing-angular';
84 | import * as stories from './button.stories'; // import all stories from the stories file
85 | import Meta from './button.stories';
86 |
87 | // Every component that is returned maps 1:1 with the stories, but they already contain all decorators from story level, meta level and global level.
88 | const { Primary, Secondary } = composeStories(stories);
89 |
90 | describe('button', () => {
91 | it('renders primary button with default args', async () => {
92 | const { component, applicationConfig } = createMountable(
93 | Primary({})
94 | );
95 | await render(component, { providers: applicationConfig.providers });
96 | const buttonElement = screen.getByText(
97 | /Text coming from args in stories file!/i
98 | );
99 | expect(buttonElement).not.toBeNull();
100 | });
101 |
102 | it('renders primary button with overriden props', async () => {
103 | const { component, applicationConfig } = createMountable(
104 | Primary({ label: 'Hello world' })
105 | ); // you can override props and they will get merged with values from the Story's args
106 | await render(component, { providers: applicationConfig.providers });
107 | const buttonElement = screen.getByText(/Hello world/i);
108 | expect(buttonElement).not.toBeNull();
109 | });
110 | });
111 | ```
112 |
113 | ### `composeStory`
114 |
115 | You can use `composeStory` if you wish to apply it for a single story rather than all of your stories. You need to pass the meta (default export) as well.
116 |
117 | ```ts
118 | import { render, screen } from '@testing-library/angular';
119 | import {
120 | composeStory,
121 | createMountable,
122 | } from '@storybook/testing-angular';
123 | import Meta, { Primary as PrimaryStory } from './button.stories';
124 |
125 | // Returns a component that already contain all decorators from story level, meta level and global level.
126 | const Primary = composeStory(PrimaryStory, Meta);
127 |
128 | describe('button', () => {
129 | it('onclick handler is called', async () => {
130 | const onClickSpy = jasmine.createSpy();
131 | const { component, applicationConfig } = createMountable(
132 | Primary({ onClick: onClickSpy })
133 | );
134 | await render(component, { provider: applicationConfig.provider });
135 | const buttonElement = screen.getByText(Primary.args?.label!);
136 | buttonElement.click();
137 | expect(onClickSpy).toHaveBeenCalled();
138 | });
139 | });
140 | ```
141 |
142 | ### Reusing story properties
143 |
144 | The components returned by `composeStories` or `composeStory` not only can be rendered as Angular components, but also come with the combined properties from story, meta and global configuration. This means that if you want to access `args` or `parameters`, for instance, you can do so:
145 |
146 | ```ts
147 | import { render, screen } from '@testing-library/angular';
148 | import {
149 | composeStory,
150 | createMountable,
151 | } from '@storybook/testing-angular';
152 | import * as stories from './button.stories';
153 | import Meta from './button.stories';
154 |
155 | const { Primary } = composeStories(stories);
156 |
157 | describe('button', () => {
158 | it('reuses args from composed story', async () => {
159 | const { component, applicationConfig } = createMountable(Primary({}));
160 | await render(component, { providers: applicationConfig.providers });
161 | expect(screen.getByText(Primary.args?.label!)).not.toBeNull();
162 | });
163 | });
164 | ```
165 |
166 | > **If you're using Typescript**: Given that some of the returned properties are not required, typescript might perceive them as nullable properties and present an error. If you are sure that they exist (e.g. certain arg that is set in the story), you can use the [non-null assertion operator](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#non-null-assertion-operator) to tell typescript that it's all good:
167 |
168 | ```tsx
169 | // ERROR: Object is possibly 'undefined'
170 | Primary.args.children;
171 |
172 | // SUCCESS: 🎉
173 | Primary.args!.children;
174 | ```
175 |
176 | ## Typescript
177 |
178 | `@storybook/testing-angular` is typescript ready and provides autocompletion to easily detect all stories of your component:
179 |
180 | 
181 |
182 | It also provides the props of the components just as you would normally expect when using them directly in your tests:
183 |
184 | 
185 |
186 | Type inference is only possible in projects that have either `strict` or `strictBindApplyCall` modes set to `true` in their `tsconfig.json` file. You also need a TypeScript version over 4.0.0. If you don't have proper type inference, this might be the reason.
187 |
188 | ```jsonc
189 | // tsconfig.json
190 | {
191 | "compilerOptions": {
192 | // ...
193 | "strict": true, // You need either this option
194 | "strictBindCallApply": true // or this option
195 | // ...
196 | }
197 | // ...
198 | }
199 | ```
200 |
201 | ### Disclaimer
202 |
203 | For the types to be automatically picked up, your stories must be typed. See an example:
204 |
205 | ```ts
206 | import { Story, Meta } from '@storybook/angular';
207 |
208 | import { ButtonComponent } from './button.component';
209 |
210 | export default {
211 | title: 'Components/Button',
212 | component: ButtonComponent,
213 | } as Meta;
214 |
215 | // Story is the key piece needed for typescript validation
216 | const Template: Story = (args: ButtonComponent) => ({
217 | props: args,
218 | });
219 |
220 | export const Primary = Template.bind({});
221 | Primary.args = {
222 | primary: true,
223 | label: 'Button',
224 | };
225 | ```
226 |
227 | ## License
228 |
229 | [MIT](./LICENSE)
230 |
--------------------------------------------------------------------------------
/example/.browserslistrc:
--------------------------------------------------------------------------------
1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
2 | # For additional information regarding the format and rule options, please see:
3 | # https://github.com/browserslist/browserslist#queries
4 |
5 | # For the full list of supported browsers by the Angular framework, please see:
6 | # https://angular.io/guide/browser-support
7 |
8 | # You can see what browsers were selected by your queries by running:
9 | # npx browserslist
10 |
11 | last 1 Chrome version
12 | last 1 Firefox version
13 | last 2 Edge major versions
14 | last 2 Safari major versions
15 | last 2 iOS major versions
16 | Firefox ESR
17 | not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
18 |
--------------------------------------------------------------------------------
/example/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # Compiled output
4 | /dist
5 | /tmp
6 | /out-tsc
7 | /bazel-out
8 |
9 | # Node
10 | /node_modules
11 | npm-debug.log
12 | yarn-error.log
13 |
14 | # IDEs and editors
15 | .idea/
16 | .project
17 | .classpath
18 | .c9/
19 | *.launch
20 | .settings/
21 | *.sublime-workspace
22 |
23 | # Visual Studio Code
24 | .vscode/*
25 | !.vscode/settings.json
26 | !.vscode/tasks.json
27 | !.vscode/launch.json
28 | !.vscode/extensions.json
29 | .history/*
30 |
31 | # Miscellaneous
32 | /.angular/cache
33 | .sass-cache/
34 | /connect.lock
35 | /coverage
36 | /libpeerconnection.log
37 | testem.log
38 | /typings
39 |
40 | # System files
41 | .DS_Store
42 | Thumbs.db
43 |
--------------------------------------------------------------------------------
/example/.storybook/main.ts:
--------------------------------------------------------------------------------
1 | import type { StorybookConfig } from '@storybook/angular';
2 | const config: StorybookConfig = {
3 | stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
4 | addons: [
5 | '@storybook/addon-links',
6 | '@storybook/addon-essentials',
7 | '@storybook/addon-interactions',
8 | ],
9 | framework: {
10 | name: '@storybook/angular',
11 | options: {},
12 | },
13 | docs: {
14 | autodocs: 'tag',
15 | },
16 | };
17 | export default config;
18 |
--------------------------------------------------------------------------------
/example/.storybook/preview.ts:
--------------------------------------------------------------------------------
1 | import type { Preview } from '@storybook/angular';
2 | import { setCompodocJson } from '@storybook/addon-docs/angular';
3 | import docJson from '../documentation.json';
4 | setCompodocJson(docJson);
5 |
6 | const preview: Preview = {
7 | parameters: {
8 | actions: { argTypesRegex: '^on[A-Z].*' },
9 | controls: {
10 | matchers: {
11 | color: /(background|color)$/i,
12 | date: /Date$/,
13 | },
14 | },
15 | },
16 | };
17 |
18 | export default preview;
19 |
--------------------------------------------------------------------------------
/example/.storybook/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.app.json",
3 | "compilerOptions": {
4 | "types": ["node"],
5 | "allowSyntheticDefaultImports": true,
6 | "resolveJsonModule": true
7 | },
8 | "exclude": ["../src/test.ts", "../src/**/*.spec.ts"],
9 | "include": ["../src/**/*", "./preview.ts"],
10 | "files": ["./typings.d.ts"]
11 | }
12 |
--------------------------------------------------------------------------------
/example/.storybook/typings.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.md' {
2 | const content: string;
3 | export default content;
4 | }
5 |
--------------------------------------------------------------------------------
/example/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/example/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
3 | "version": "0.2.0",
4 | "configurations": [
5 | {
6 | "name": "ng serve",
7 | "type": "chrome",
8 | "request": "launch",
9 | "preLaunchTask": "npm: start",
10 | "url": "http://localhost:4200/"
11 | },
12 | {
13 | "name": "ng test",
14 | "type": "chrome",
15 | "request": "launch",
16 | "preLaunchTask": "npm: test",
17 | "url": "http://localhost:9876/debug.html"
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/example/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
3 | "version": "2.0.0",
4 | "tasks": [
5 | {
6 | "type": "npm",
7 | "script": "start",
8 | "isBackground": true,
9 | "problemMatcher": {
10 | "owner": "typescript",
11 | "pattern": "$tsc",
12 | "background": {
13 | "activeOnStart": true,
14 | "beginsPattern": {
15 | "regexp": "(.*?)"
16 | },
17 | "endsPattern": {
18 | "regexp": "bundle generation complete"
19 | }
20 | }
21 | }
22 | },
23 | {
24 | "type": "npm",
25 | "script": "test",
26 | "isBackground": true,
27 | "problemMatcher": {
28 | "owner": "typescript",
29 | "pattern": "$tsc",
30 | "background": {
31 | "activeOnStart": true,
32 | "beginsPattern": {
33 | "regexp": "(.*?)"
34 | },
35 | "endsPattern": {
36 | "regexp": "bundle generation complete"
37 | }
38 | }
39 | }
40 | }
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 16.0.2.
4 |
5 | ## Development server
6 |
7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
8 |
9 | ## Code scaffolding
10 |
11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
12 |
13 | ## Build
14 |
15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
16 |
17 | ## Running unit tests
18 |
19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
20 |
21 | ## Running end-to-end tests
22 |
23 | Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
24 |
25 | ## Further help
26 |
27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
28 |
--------------------------------------------------------------------------------
/example/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "example": {
7 | "projectType": "application",
8 | "schematics": {
9 | "@schematics/angular:component": {
10 | "style": "scss"
11 | }
12 | },
13 | "root": "",
14 | "sourceRoot": "src",
15 | "prefix": "app",
16 | "architect": {
17 | "build": {
18 | "builder": "@angular-devkit/build-angular:application",
19 | "options": {
20 | "outputPath": {
21 | "base": "dist/example"
22 | },
23 | "index": "src/index.html",
24 | "polyfills": ["zone.js"],
25 | "tsConfig": "tsconfig.app.json",
26 | "inlineStyleLanguage": "scss",
27 | "assets": ["src/favicon.ico", "src/assets"],
28 | "styles": ["src/styles.scss"],
29 | "scripts": [],
30 | "sourceMap": true,
31 | "browser": "src/main.ts"
32 | },
33 | "configurations": {
34 | "production": {
35 | "budgets": [
36 | {
37 | "type": "initial",
38 | "maximumWarning": "500kb",
39 | "maximumError": "1mb"
40 | },
41 | {
42 | "type": "anyComponentStyle",
43 | "maximumWarning": "2kb",
44 | "maximumError": "4kb"
45 | }
46 | ],
47 | "outputHashing": "all"
48 | },
49 | "development": {
50 | "optimization": false,
51 | "extractLicenses": false,
52 | "sourceMap": true,
53 | "namedChunks": true
54 | }
55 | },
56 | "defaultConfiguration": "production"
57 | },
58 | "serve": {
59 | "builder": "@angular-devkit/build-angular:dev-server",
60 | "configurations": {
61 | "production": {
62 | "buildTarget": "example:build:production"
63 | },
64 | "development": {
65 | "buildTarget": "example:build:development"
66 | }
67 | },
68 | "defaultConfiguration": "development"
69 | },
70 | "extract-i18n": {
71 | "builder": "@angular-devkit/build-angular:extract-i18n",
72 | "options": {
73 | "buildTarget": "example:build"
74 | }
75 | },
76 | "test": {
77 | "builder": "@angular-devkit/build-angular:karma",
78 | "options": {
79 | "polyfills": ["zone.js", "zone.js/testing"],
80 | "tsConfig": "tsconfig.spec.json",
81 | "inlineStyleLanguage": "scss",
82 | "assets": ["src/favicon.ico", "src/assets"],
83 | "styles": ["src/styles.scss"],
84 | "scripts": [],
85 | "sourceMap": true
86 | }
87 | },
88 | "storybook": {
89 | "builder": "@storybook/angular:start-storybook",
90 | "options": {
91 | "configDir": ".storybook",
92 | "browserTarget": "example:build",
93 | "compodoc": true,
94 | "compodocArgs": ["-e", "json", "-d", "."],
95 | "port": 6009,
96 | "open": false
97 | }
98 | },
99 | "build-storybook": {
100 | "builder": "@storybook/angular:build-storybook",
101 | "options": {
102 | "configDir": ".storybook",
103 | "browserTarget": "example:build",
104 | "compodoc": true,
105 | "compodocArgs": ["-e", "json", "-d", "."],
106 | "outputDir": "storybook-static"
107 | }
108 | }
109 | }
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/example/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage'),
13 | require('@angular-devkit/build-angular/plugins/karma')
14 | ],
15 | client: {
16 | jasmine: {
17 | // you can add configuration options for Jasmine here
18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
19 | // for example, you can disable the random execution with `random: false`
20 | // or set a specific seed with `seed: 4321`
21 | },
22 | clearContext: false // leave Jasmine Spec Runner output visible in browser
23 | },
24 | jasmineHtmlReporter: {
25 | suppressAll: true // removes the duplicated traces
26 | },
27 | coverageReporter: {
28 | dir: require('path').join(__dirname, './coverage/example'),
29 | subdir: '.',
30 | reporters: [
31 | { type: 'html' },
32 | { type: 'text-summary' }
33 | ]
34 | },
35 | reporters: ['progress', 'kjhtml'],
36 | port: 9876,
37 | colors: true,
38 | logLevel: config.LOG_INFO,
39 | autoWatch: true,
40 | browsers: ['Chrome'],
41 | singleRun: false,
42 | restartOnFileChange: true
43 | });
44 | };
45 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "0.0.0",
4 | "scripts": {
5 | "ng": "ng",
6 | "start": "ng serve",
7 | "build": "ng build",
8 | "watch": "ng build --watch --configuration development",
9 | "test": "ng test",
10 | "storybook": "ng run example:storybook",
11 | "build-storybook": "ng run example:build-storybook"
12 | },
13 | "private": true,
14 | "dependencies": {
15 | "@angular/animations": "^18.0.1",
16 | "@angular/common": "^18.0.1",
17 | "@angular/compiler": "^18.0.1",
18 | "@angular/core": "^18.0.1",
19 | "@angular/forms": "^18.0.1",
20 | "@angular/platform-browser": "^18.0.1",
21 | "@angular/platform-browser-dynamic": "^18.0.1",
22 | "@angular/router": "^18.0.1",
23 | "@ngrx/store": "^17.2.0",
24 | "@testing-library/angular": "^14.1.1",
25 | "rxjs": "~7.8.0",
26 | "tslib": "^2.6.2",
27 | "zone.js": "~0.14.6"
28 | },
29 | "devDependencies": {
30 | "@angular-devkit/build-angular": "^18.0.2",
31 | "@angular/cli": "~18.0.2",
32 | "@angular/compiler-cli": "^18.0.1",
33 | "@compodoc/compodoc": "^1.1.21",
34 | "@storybook/addon-essentials": "^8.1.5",
35 | "@storybook/addon-interactions": "^8.1.5",
36 | "@storybook/addon-links": "^8.1.5",
37 | "@storybook/angular": "^8.1.5",
38 | "@storybook/blocks": "^8.1.5",
39 | "@types/jasmine": "~4.3.0",
40 | "jasmine-core": "~4.6.0",
41 | "karma": "~6.4.0",
42 | "karma-chrome-launcher": "~3.2.0",
43 | "karma-coverage": "~2.2.0",
44 | "karma-jasmine": "~5.1.0",
45 | "karma-jasmine-html-reporter": "~2.0.0",
46 | "react": "^18.2.0",
47 | "react-dom": "^18.2.0",
48 | "storybook": "^8.1.5",
49 | "typescript": "~5.4.5"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/example/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
304 |
305 |
306 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 | Rocket Ship
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
{{ title }} app is running!
345 |
346 |
347 | Rocket Ship Smoke
348 |
349 |
350 |
351 |
352 |
353 |
354 |
Resources
355 |
Here are some links to help you get started:
356 |
357 |
388 |
389 |
390 |
Next Steps
391 |
What do you want to do next with your app?
392 |
393 |
394 |
395 |
396 |
397 |
398 | New Component
399 |
400 |
401 |
402 |
403 | Angular Material
404 |
405 |
406 |
407 |
408 | Add PWA Support
409 |
410 |
411 |
412 |
413 | Add Dependency
414 |
415 |
416 |
417 |
418 | Run and Watch Tests
419 |
420 |
421 |
422 |
423 | Build for Production
424 |
425 |
426 |
427 |
428 |
429 |
ng generate component xyz
430 |
ng add @angular/material
431 |
ng add @angular/pwa
432 |
ng add _____
433 |
ng test
434 |
ng build
435 |
436 |
437 |
438 |
454 |
455 |
456 |
468 |
469 |
470 | Gray Clouds Background
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
--------------------------------------------------------------------------------
/example/src/app/app.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storybookjs/testing-angular/52995bb0d2ff1daaddca54430d626ec42d8dc1eb/example/src/app/app.component.scss
--------------------------------------------------------------------------------
/example/src/app/app.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 | import { AppComponent } from './app.component';
3 |
4 | describe('AppComponent', () => {
5 | beforeEach(() => TestBed.configureTestingModule({
6 | declarations: [AppComponent]
7 | }));
8 |
9 | it('should create the app', () => {
10 | const fixture = TestBed.createComponent(AppComponent);
11 | const app = fixture.componentInstance;
12 | expect(app).toBeTruthy();
13 | });
14 |
15 | it(`should have as title 'example'`, () => {
16 | const fixture = TestBed.createComponent(AppComponent);
17 | const app = fixture.componentInstance;
18 | expect(app.title).toEqual('example');
19 | });
20 |
21 | it('should render title', () => {
22 | const fixture = TestBed.createComponent(AppComponent);
23 | fixture.detectChanges();
24 | const compiled = fixture.nativeElement as HTMLElement;
25 | expect(compiled.querySelector('.content span')?.textContent).toContain('example app is running!');
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/example/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | templateUrl: './app.component.html',
6 | styleUrls: ['./app.component.scss']
7 | })
8 | export class AppComponent {
9 | title = 'example';
10 | }
11 |
--------------------------------------------------------------------------------
/example/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { BrowserModule } from '@angular/platform-browser';
3 |
4 | import { AppComponent } from './app.component';
5 |
6 | @NgModule({
7 | declarations: [
8 | AppComponent
9 | ],
10 | imports: [
11 | BrowserModule
12 | ],
13 | providers: [],
14 | bootstrap: [AppComponent]
15 | })
16 | export class AppModule { }
17 |
--------------------------------------------------------------------------------
/example/src/app/ngrx/counter.actions.ts:
--------------------------------------------------------------------------------
1 | import { createAction } from '@ngrx/store';
2 |
3 | export const increment = createAction('[Counter Component] Increment');
4 | export const decrement = createAction('[Counter Component] Decrement');
5 | export const reset = createAction('[Counter Component] Reset');
6 |
--------------------------------------------------------------------------------
/example/src/app/ngrx/counter.reducer.ts:
--------------------------------------------------------------------------------
1 | import { createReducer, on } from '@ngrx/store';
2 | import { increment, decrement, reset } from './counter.actions';
3 |
4 | export const initialState = 0;
5 |
6 | export const counterReducer = createReducer(
7 | initialState,
8 | on(increment, (state) => state + 1),
9 | on(decrement, (state) => state - 1),
10 | on(reset, (state) => 0)
11 | );
12 |
--------------------------------------------------------------------------------
/example/src/app/ngrx/my-counter.component.html:
--------------------------------------------------------------------------------
1 | Increment
2 |
3 | Current Count: {{ count$ | async }}
4 |
5 | Decrement
6 |
7 | Reset Counter
--------------------------------------------------------------------------------
/example/src/app/ngrx/my-counter.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { Store } from '@ngrx/store';
3 | import { Observable } from 'rxjs';
4 |
5 | import { increment, decrement, reset } from './counter.actions';
6 |
7 | @Component({
8 | selector: 'app-my-counter',
9 | templateUrl: './my-counter.component.html',
10 | })
11 | export class MyCounterComponent {
12 | count$: Observable;
13 |
14 | constructor(private store: Store<{ count: number }>) {
15 | this.count$ = store.select('count');
16 | }
17 |
18 | increment() {
19 | this.store.dispatch(increment());
20 | }
21 |
22 | decrement() {
23 | this.store.dispatch(decrement());
24 | }
25 |
26 | reset() {
27 | this.store.dispatch(reset());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/example/src/app/ngrx/my-counter.spec.ts:
--------------------------------------------------------------------------------
1 | import { composeStories, composeStory, createMountable } from '@storybook/testing-angular';
2 |
3 | import { render, screen } from '@testing-library/angular';
4 |
5 | import * as stories from './my-counter.stories';
6 | import meta, { Primary } from './my-counter.stories';
7 |
8 | const composed = composeStories(stories);
9 |
10 | const _Primary = composeStory(Primary, meta);
11 |
12 | describe('interactive stories test', () => {
13 | describe('composeStories', () => {
14 | it('should render and validate story', async () => {
15 | const { component, applicationConfig } = createMountable(composed.Primary({}));
16 | await render(component, { providers: applicationConfig.providers });
17 | expect(screen.getByText("Current Count: 0")).not.toBeNull();
18 | });
19 | });
20 |
21 | describe('composeStory', () => {
22 | it('should render and validate story', async () => {
23 | const { component, applicationConfig } = createMountable(_Primary({}));
24 | await render(component, { providers: applicationConfig.providers });
25 | expect(screen.getByText("Current Count: 0")).not.toBeNull();
26 | });
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/example/src/app/ngrx/my-counter.stories.ts:
--------------------------------------------------------------------------------
1 | import { Meta, applicationConfig } from '@storybook/angular';
2 |
3 | import { provideStore } from '@ngrx/store';
4 |
5 | import { counterReducer } from './counter.reducer';
6 | import { MyCounterComponent } from './my-counter.component';
7 |
8 | export default {
9 | title: 'NGRX/MyCounter',
10 | component: MyCounterComponent,
11 | decorators: [
12 | applicationConfig({
13 | providers: [
14 | provideStore({ count: counterReducer })
15 | ],
16 | }),
17 | ],
18 | } as Meta;
19 |
20 | export const Primary = {
21 | render: (args: MyCounterComponent) => ({
22 | props: args,
23 | }),
24 | args: {},
25 | };
26 |
--------------------------------------------------------------------------------
/example/src/app/signal/with-signal-input.component.ts:
--------------------------------------------------------------------------------
1 | import { CommonModule } from '@angular/common';
2 | import { Component, input } from '@angular/core';
3 |
4 | @Component({
5 | selector: 'app-with-signal-input',
6 | template: `Is Primary: {{ primary() }}
`,
7 | standalone: true,
8 | imports: [
9 | CommonModule,
10 | ],
11 | })
12 | export default class WithSignalInputComponent {
13 | primary = input(false);
14 | }
15 |
--------------------------------------------------------------------------------
/example/src/app/signal/with-signal-input.spec.ts:
--------------------------------------------------------------------------------
1 | import { composeStories, createMountable } from '@storybook/testing-angular';
2 |
3 | import { render, screen } from '@testing-library/angular';
4 |
5 | import * as stories from './with-signal-input.stories';
6 |
7 | const composed = composeStories(stories);
8 |
9 | describe('with signal input stories test', () =>
10 | it('should render and validate story', async () => {
11 | const { component, applicationConfig } = createMountable(composed.Primary({}));
12 | await render(component, { providers: applicationConfig.providers });
13 | expect(screen.getByText("Is Primary: false")).not.toBeNull();
14 | }));
15 |
--------------------------------------------------------------------------------
/example/src/app/signal/with-signal-input.stories.ts:
--------------------------------------------------------------------------------
1 | import { Meta, StoryObj } from '@storybook/angular';
2 |
3 | import WithSignalInputComponent from './with-signal-input.component';
4 |
5 | export default {
6 | title: 'Signal/WithSignalInput',
7 | component: WithSignalInputComponent,
8 | } as Meta;
9 |
10 | export const Primary: StoryObj = {};
11 |
--------------------------------------------------------------------------------
/example/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storybookjs/testing-angular/52995bb0d2ff1daaddca54430d626ec42d8dc1eb/example/src/assets/.gitkeep
--------------------------------------------------------------------------------
/example/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true
3 | };
4 |
--------------------------------------------------------------------------------
/example/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // This file can be replaced during build by using the `fileReplacements` array.
2 | // `ng build` replaces `environment.ts` with `environment.prod.ts`.
3 | // The list of file replacements can be found in `angular.json`.
4 |
5 | export const environment = {
6 | production: false
7 | };
8 |
9 | /*
10 | * For easier debugging in development mode, you can import the following file
11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
12 | *
13 | * This import should be commented out in production mode because it will have a negative impact
14 | * on performance if an error is thrown.
15 | */
16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI.
17 |
--------------------------------------------------------------------------------
/example/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storybookjs/testing-angular/52995bb0d2ff1daaddca54430d626ec42d8dc1eb/example/src/favicon.ico
--------------------------------------------------------------------------------
/example/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 |
3 | import { AppModule } from './app/app.module';
4 |
5 |
6 | platformBrowserDynamic().bootstrapModule(AppModule)
7 | .catch(err => console.error(err));
8 |
--------------------------------------------------------------------------------
/example/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/guide/browser-support
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /**
22 | * IE11 requires the following for NgClass support on SVG elements
23 | */
24 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
25 |
26 | /**
27 | * Web Animations `@angular/platform-browser/animations`
28 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
29 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
30 | */
31 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
32 |
33 | /**
34 | * By default, zone.js will patch all possible macroTask and DomEvents
35 | * user can disable parts of macroTask/DomEvents patch by setting following flags
36 | * because those flags need to be set before `zone.js` being loaded, and webpack
37 | * will put import in the top of bundle, so user need to create a separate file
38 | * in this directory (for example: zone-flags.ts), and put the following flags
39 | * into that file, and then add the following code before importing zone.js.
40 | * import './zone-flags';
41 | *
42 | * The flags allowed in zone-flags.ts are listed here.
43 | *
44 | * The following flags will work for all browsers.
45 | *
46 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
47 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
48 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
49 | *
50 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
51 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
52 | *
53 | * (window as any).__Zone_enable_cross_context_check = true;
54 | *
55 | */
56 |
57 | /***************************************************************************************************
58 | * Zone JS is required by default for Angular itself.
59 | */
60 | import 'zone.js'; // Included with Angular CLI.
61 |
62 |
63 | /***************************************************************************************************
64 | * APPLICATION IMPORTS
65 | */
66 |
--------------------------------------------------------------------------------
/example/src/stories/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "@typescript-eslint/consistent-type-imports": ["error", { "disallowTypeAnnotations": false }]
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/example/src/stories/Button.stories.ts:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/angular';
2 | import { ButtonComponent } from './button.component';
3 |
4 | // More on how to set up stories at: https://storybook.js.org/docs/angular/writing-stories/introduction
5 | const meta: Meta = {
6 | title: 'Example/Button',
7 | component: ButtonComponent,
8 | tags: ['autodocs'],
9 | render: args => ({
10 | props: {
11 | backgroundColor: null,
12 | ...args,
13 | },
14 | }),
15 | argTypes: {
16 | backgroundColor: {
17 | control: 'color',
18 | },
19 | },
20 | };
21 |
22 | export default meta;
23 | type Story = StoryObj;
24 |
25 | // More on writing stories with args: https://storybook.js.org/docs/angular/writing-stories/args
26 | export const Primary: Story = {
27 | args: {
28 | primary: true,
29 | label: 'Button',
30 | },
31 | };
32 |
33 | export const Secondary: Story = {
34 | args: {
35 | label: 'Button',
36 | },
37 | };
38 |
39 | export const Large: Story = {
40 | args: {
41 | size: 'large',
42 | label: 'Button',
43 | },
44 | };
45 |
46 | export const Small: Story = {
47 | args: {
48 | size: 'small',
49 | label: 'Button',
50 | },
51 | };
52 |
53 | export const Other: Story = {
54 | render: args => ({
55 | props: args,
56 | template: ` `
57 | }),
58 | args: {
59 | primary: true,
60 | label: 'Button',
61 | },
62 | };
63 |
--------------------------------------------------------------------------------
/example/src/stories/Header.stories.ts:
--------------------------------------------------------------------------------
1 | import { moduleMetadata } from '@storybook/angular';
2 | import type { Meta, StoryObj } from '@storybook/angular';
3 | import { CommonModule } from '@angular/common';
4 |
5 | import { ButtonComponent } from './button.component';
6 | import Header from './header.component';
7 |
8 | const meta: Meta