@dotjem/angular-dynamic-components 0.0.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 (41) hide show
  1. package/.editorconfig +17 -0
  2. package/.github/workflows/ci-publish.yml +113 -0
  3. package/.prettierrc +12 -0
  4. package/.vscode/extensions.json +4 -0
  5. package/.vscode/launch.json +20 -0
  6. package/.vscode/mcp.json +9 -0
  7. package/.vscode/tasks.json +42 -0
  8. package/LICENSE +21 -0
  9. package/README.md +153 -0
  10. package/angular-dynamic-components-0.0.0.tgz +0 -0
  11. package/angular.json +102 -0
  12. package/dotjem-angular-dynamic-components-0.0.1.tgz +0 -0
  13. package/package.json +34 -0
  14. package/projects/demo/public/favicon.ico +0 -0
  15. package/projects/demo/src/app/app.config.ts +30 -0
  16. package/projects/demo/src/app/app.html +41 -0
  17. package/projects/demo/src/app/app.routes.ts +3 -0
  18. package/projects/demo/src/app/app.scss +0 -0
  19. package/projects/demo/src/app/app.spec.ts +27 -0
  20. package/projects/demo/src/app/app.ts +117 -0
  21. package/projects/demo/src/app/components/search-text-field.component.ts +49 -0
  22. package/projects/demo/src/app/components/section-heading.component.ts +25 -0
  23. package/projects/demo/src/app/components/select-field.component.ts +56 -0
  24. package/projects/demo/src/app/components/text-field.component.ts +53 -0
  25. package/projects/demo/src/index.html +13 -0
  26. package/projects/demo/src/main.ts +5 -0
  27. package/projects/demo/src/styles.scss +1 -0
  28. package/projects/demo/tsconfig.app.json +11 -0
  29. package/projects/demo/tsconfig.spec.json +10 -0
  30. package/projects/dotjem/angular-dynamic-components/README.md +5 -0
  31. package/projects/dotjem/angular-dynamic-components/ng-package.json +7 -0
  32. package/projects/dotjem/angular-dynamic-components/package.json +27 -0
  33. package/projects/dotjem/angular-dynamic-components/src/lib/component-registry.spec.ts +127 -0
  34. package/projects/dotjem/angular-dynamic-components/src/lib/component-registry.ts +137 -0
  35. package/projects/dotjem/angular-dynamic-components/src/lib/dynamic-component-host.component.spec.ts +151 -0
  36. package/projects/dotjem/angular-dynamic-components/src/lib/dynamic-component-host.component.ts +135 -0
  37. package/projects/dotjem/angular-dynamic-components/src/public-api.ts +6 -0
  38. package/projects/dotjem/angular-dynamic-components/tsconfig.lib.json +13 -0
  39. package/projects/dotjem/angular-dynamic-components/tsconfig.lib.prod.json +11 -0
  40. package/projects/dotjem/angular-dynamic-components/tsconfig.spec.json +10 -0
  41. package/tsconfig.json +42 -0
package/.editorconfig ADDED
@@ -0,0 +1,17 @@
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
+ ij_typescript_use_double_quotes = false
14
+
15
+ [*.md]
16
+ max_line_length = off
17
+ trim_trailing_whitespace = false
@@ -0,0 +1,113 @@
1
+ name: CI and Publish
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches:
7
+ - main
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ verify:
14
+ name: Build, Test and Report
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - name: Checkout
18
+ uses: actions/checkout@v4
19
+
20
+ - name: Setup Node.js
21
+ uses: actions/setup-node@v4
22
+ with:
23
+ node-version: 22
24
+ cache: npm
25
+
26
+ - name: Install dependencies
27
+ run: npm ci
28
+
29
+ - name: Run tests
30
+ run: npm test
31
+
32
+ - name: Build library
33
+ run: npm run build
34
+
35
+ - name: Upload build artifact
36
+ uses: actions/upload-artifact@v4
37
+ with:
38
+ name: dotjem-angular-dynamic-components-dist
39
+ path: dist/dotjem/angular-dynamic-components
40
+ if-no-files-found: error
41
+
42
+ publish:
43
+ name: Publish to npm
44
+ runs-on: ubuntu-latest
45
+ needs: verify
46
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
47
+ env:
48
+ LIB_PACKAGE_DIR: projects/dotjem/angular-dynamic-components
49
+ LIB_DIST_DIR: dist/dotjem/angular-dynamic-components
50
+ steps:
51
+ - name: Checkout
52
+ uses: actions/checkout@v4
53
+
54
+ - name: Setup Node.js for npm publish
55
+ uses: actions/setup-node@v4
56
+ with:
57
+ node-version: 22
58
+ cache: npm
59
+ registry-url: https://registry.npmjs.org
60
+
61
+ - name: Install dependencies
62
+ run: npm ci
63
+
64
+ - name: Calculate Version Parameters
65
+ id: version
66
+ run: |
67
+ set -euo pipefail
68
+ build="${GITHUB_RUN_NUMBER}"
69
+ template="$(node -p "require('./${LIB_PACKAGE_DIR}/package.json').version")"
70
+ shortsha="$(git rev-parse --short "${GITHUB_SHA}")"
71
+ base="$(node - "$template" "$build" <<'NODE'
72
+ const template = process.argv[2];
73
+ const build = process.argv[3];
74
+ const parts = template.split('.');
75
+ const index = parts.indexOf('build');
76
+
77
+ if (index >= 0) {
78
+ parts[index] = build;
79
+ process.stdout.write(parts.join('.'));
80
+ } else {
81
+ process.stdout.write(`${template}-${build}`);
82
+ }
83
+ NODE
84
+ )"
85
+ publish_version="${base}+sha.${shortsha}"
86
+
87
+ echo "template=$template" >> "$GITHUB_OUTPUT"
88
+ echo "shortsha=$shortsha" >> "$GITHUB_OUTPUT"
89
+ echo "publish_version=$publish_version" >> "$GITHUB_OUTPUT"
90
+
91
+ {
92
+ echo "### Version Parameters"
93
+ echo "- template: \`$template\`"
94
+ echo "- run number: \`$build\`"
95
+ echo "- short sha: \`$shortsha\`"
96
+ echo "- publish version: \`$publish_version\`"
97
+ } >> "$GITHUB_STEP_SUMMARY"
98
+
99
+ - name: Set package version
100
+ run: |
101
+ npm pkg set version="${{ steps.version.outputs.publish_version }}" --prefix "${LIB_PACKAGE_DIR}"
102
+
103
+ - name: Build library
104
+ run: npm run build
105
+
106
+ - name: Set dist package version
107
+ run: |
108
+ npm pkg set version="${{ steps.version.outputs.publish_version }}" --prefix "${LIB_DIST_DIR}"
109
+
110
+ - name: Publish package
111
+ run: npm publish "./${LIB_DIST_DIR}" --access public
112
+ env:
113
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH }}
package/.prettierrc ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "printWidth": 100,
3
+ "singleQuote": true,
4
+ "overrides": [
5
+ {
6
+ "files": "*.html",
7
+ "options": {
8
+ "parser": "angular"
9
+ }
10
+ }
11
+ ]
12
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3
+ "recommendations": ["angular.ng-template"]
4
+ }
@@ -0,0 +1,20 @@
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
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ // For more information, visit: https://angular.dev/ai/mcp
3
+ "servers": {
4
+ "angular-cli": {
5
+ "command": "npx",
6
+ "args": ["-y", "@angular/cli", "mcp"]
7
+ }
8
+ }
9
+ }
@@ -0,0 +1,42 @@
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": "Changes detected"
16
+ },
17
+ "endsPattern": {
18
+ "regexp": "bundle generation (complete|failed)"
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": "Changes detected"
34
+ },
35
+ "endsPattern": {
36
+ "regexp": "bundle generation (complete|failed)"
37
+ }
38
+ }
39
+ }
40
+ }
41
+ ]
42
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dotJEM
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,153 @@
1
+ # @dotjem/angular-dynamic-components
2
+
3
+ > Dynamic component hosting for Angular 21+ — render registered components configured as plain JSON.
4
+
5
+ Use `dx-dynamic-component-host` directly and let your application own iteration, data mapping, and configuration shape.
6
+
7
+ ---
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @dotjem/angular-dynamic-components
13
+ ```
14
+
15
+ > **Peer dependencies:** `@angular/core ^21`, `@angular/common ^21`, `@angular/forms ^21`
16
+
17
+ ---
18
+
19
+ ## Quick start
20
+
21
+ ### 1. Register your components
22
+
23
+ In your `app.config.ts` (or any `providers` array) call `provideDynamicComponents()`:
24
+
25
+ ```ts
26
+ import { provideDynamicComponents } from '@dotjem/angular-dynamic-components';
27
+ import { TextFieldComponent } from './fields/text-field.component';
28
+ import { SelectFieldComponent } from './fields/select-field.component';
29
+
30
+ export const appConfig: ApplicationConfig = {
31
+ providers: [
32
+ provideDynamicComponents(
33
+ {
34
+ 'text-field': TextFieldComponent,
35
+ 'select-field': SelectFieldComponent,
36
+ },
37
+ 'editor'
38
+ ),
39
+ provideDynamicComponents(
40
+ {
41
+ 'text-field': SearchTextFieldComponent,
42
+ },
43
+ 'search'
44
+ ),
45
+ ],
46
+ };
47
+ ```
48
+
49
+ ### 2. Describe your UI as configuration entries
50
+
51
+ ```ts
52
+ type DynamicConfiguration = {
53
+ type: string;
54
+ field?: string;
55
+ config: Record<string, unknown>;
56
+ };
57
+
58
+ const editorConfigurations: DynamicConfiguration[] = [
59
+ { type: 'section-heading', config: { title: 'Personal Information' } },
60
+ {
61
+ type: 'text-field',
62
+ field: 'firstName',
63
+ config: { name: 'firstName', label: 'First name', placeholder: 'Jane' },
64
+ },
65
+ ];
66
+
67
+ let editorData: Record<string, unknown> = {
68
+ firstName: { value: 'Jane' },
69
+ };
70
+ ```
71
+
72
+ ### 3. Render with `<dx-dynamic-component-host>`
73
+
74
+ ```html
75
+ @for (entry of editorConfigurations; track $index) {
76
+ <dx-dynamic-component-host
77
+ [component]="entry.type"
78
+ registry="editor"
79
+ [data]="entry.field ? editorData[entry.field] : undefined"
80
+ [config]="entry.config"
81
+ (dataChange)="onFieldChange(entry.field, $event)"
82
+ />
83
+ }
84
+ ```
85
+
86
+ ---
87
+
88
+ ## API
89
+
90
+ ### `ComponentRegistry`
91
+
92
+ Injectable service. Use it when you need to register components imperatively:
93
+
94
+ ```ts
95
+ import { ComponentRegistry } from '@dotjem/angular-dynamic-components';
96
+
97
+ export class SomeModule {
98
+ constructor(registry: ComponentRegistry) {
99
+ registry.register('my-widget', MyWidgetComponent);
100
+ }
101
+ }
102
+ ```
103
+
104
+ | Method | Description |
105
+ |---|---|
106
+ | `register(type, component, registry?)` | Register a component in a named registry (`default` if omitted). |
107
+ | `resolve(type, registry?)` | Returns the component class or `null` in the selected registry. |
108
+ | `has(type, registry?)` | Returns `true` if the type is registered in the selected registry. |
109
+ | `types(registry?)` | Returns registered type keys for the selected registry. |
110
+ | `registryNames()` | Returns all known registry names. |
111
+
112
+ ### `provideDynamicComponents(map, registry?)`
113
+
114
+ Creates an Angular multi-provider that pre-populates a named registry at bootstrap time.
115
+
116
+ ### `<dx-dynamic-component-host [component]="...">`
117
+
118
+ Renders the single component described by a registered component key.
119
+ Accepts host-level `[data]` and `[config]` inputs.
120
+ Re-emits the rendered component's `dataChange` so `[(data)]`-style flows work naturally.
121
+
122
+ ---
123
+
124
+ ## Demo application
125
+
126
+ ```bash
127
+ # Build the library first
128
+ npm run build
129
+
130
+ # Serve the demo app
131
+ npm start
132
+ ```
133
+
134
+ ---
135
+
136
+ ## Development
137
+
138
+ ```bash
139
+ # Run library unit tests
140
+ npm test
141
+
142
+ # Build the library
143
+ npm run build
144
+
145
+ # Build the demo application
146
+ npm run build:demo
147
+ ```
148
+
149
+ ---
150
+
151
+ ## License
152
+
153
+ MIT
package/angular.json ADDED
@@ -0,0 +1,102 @@
1
+ {
2
+ "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3
+ "version": 1,
4
+ "cli": {
5
+ "packageManager": "npm"
6
+ },
7
+ "newProjectRoot": "projects",
8
+ "projects": {
9
+ "@dotjem/angular-dynamic-components": {
10
+ "projectType": "library",
11
+ "root": "projects/dotjem/angular-dynamic-components",
12
+ "sourceRoot": "projects/dotjem/angular-dynamic-components/src",
13
+ "prefix": "dotjem",
14
+ "architect": {
15
+ "build": {
16
+ "builder": "@angular/build:ng-packagr",
17
+ "configurations": {
18
+ "production": {
19
+ "tsConfig": "projects/dotjem/angular-dynamic-components/tsconfig.lib.prod.json"
20
+ },
21
+ "development": {
22
+ "tsConfig": "projects/dotjem/angular-dynamic-components/tsconfig.lib.json"
23
+ }
24
+ },
25
+ "defaultConfiguration": "production"
26
+ },
27
+ "test": {
28
+ "builder": "@angular/build:unit-test",
29
+ "options": {
30
+ "tsConfig": "projects/dotjem/angular-dynamic-components/tsconfig.spec.json"
31
+ }
32
+ }
33
+ }
34
+ },
35
+ "demo": {
36
+ "projectType": "application",
37
+ "schematics": {
38
+ "@schematics/angular:component": {
39
+ "style": "scss"
40
+ }
41
+ },
42
+ "root": "projects/demo",
43
+ "sourceRoot": "projects/demo/src",
44
+ "prefix": "app",
45
+ "architect": {
46
+ "build": {
47
+ "builder": "@angular/build:application",
48
+ "options": {
49
+ "browser": "projects/demo/src/main.ts",
50
+ "tsConfig": "projects/demo/tsconfig.app.json",
51
+ "inlineStyleLanguage": "scss",
52
+ "assets": [
53
+ {
54
+ "glob": "**/*",
55
+ "input": "projects/demo/public"
56
+ }
57
+ ],
58
+ "styles": ["projects/demo/src/styles.scss"]
59
+ },
60
+ "configurations": {
61
+ "production": {
62
+ "budgets": [
63
+ {
64
+ "type": "initial",
65
+ "maximumWarning": "500kB",
66
+ "maximumError": "1MB"
67
+ },
68
+ {
69
+ "type": "anyComponentStyle",
70
+ "maximumWarning": "4kB",
71
+ "maximumError": "8kB"
72
+ }
73
+ ],
74
+ "outputHashing": "all"
75
+ },
76
+ "development": {
77
+ "optimization": false,
78
+ "extractLicenses": false,
79
+ "sourceMap": true
80
+ }
81
+ },
82
+ "defaultConfiguration": "production"
83
+ },
84
+ "serve": {
85
+ "builder": "@angular/build:dev-server",
86
+ "configurations": {
87
+ "production": {
88
+ "buildTarget": "demo:build:production"
89
+ },
90
+ "development": {
91
+ "buildTarget": "demo:build:development"
92
+ }
93
+ },
94
+ "defaultConfiguration": "development"
95
+ },
96
+ "test": {
97
+ "builder": "@angular/build:unit-test"
98
+ }
99
+ }
100
+ }
101
+ }
102
+ }
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@dotjem/angular-dynamic-components",
3
+ "version": "0.0.1",
4
+ "scripts": {
5
+ "ng": "ng",
6
+ "start": "ng serve demo",
7
+ "build": "ng build @dotjem/angular-dynamic-components",
8
+ "build:demo": "ng build demo",
9
+ "watch": "ng build @dotjem/angular-dynamic-components --watch --configuration development",
10
+ "test": "ng test @dotjem/angular-dynamic-components",
11
+ "test:demo": "ng test demo"
12
+ },
13
+ "packageManager": "npm@10.8.2",
14
+ "dependencies": {
15
+ "@angular/common": "^21.2.0",
16
+ "@angular/compiler": "^21.2.0",
17
+ "@angular/core": "^21.2.0",
18
+ "@angular/forms": "^21.2.0",
19
+ "@angular/platform-browser": "^21.2.0",
20
+ "@angular/router": "^21.2.0",
21
+ "rxjs": "~7.8.0",
22
+ "tslib": "^2.3.0"
23
+ },
24
+ "devDependencies": {
25
+ "@angular/build": "^21.2.11",
26
+ "@angular/cli": "^21.2.11",
27
+ "@angular/compiler-cli": "^21.2.0",
28
+ "jsdom": "^28.0.0",
29
+ "ng-packagr": "^21.2.0",
30
+ "prettier": "^3.8.1",
31
+ "typescript": "~5.9.2",
32
+ "vitest": "^4.0.8"
33
+ }
34
+ }
Binary file
@@ -0,0 +1,30 @@
1
+ import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
2
+ import { provideRouter } from '@angular/router';
3
+ import { provideDynamicComponents } from '@dotjem/angular-dynamic-components';
4
+
5
+ import { routes } from './app.routes';
6
+ import { TextFieldComponent } from './components/text-field.component';
7
+ import { SelectFieldComponent } from './components/select-field.component';
8
+ import { SectionHeadingComponent } from './components/section-heading.component';
9
+ import { SearchTextFieldComponent } from './components/search-text-field.component';
10
+
11
+ export const appConfig: ApplicationConfig = {
12
+ providers: [
13
+ provideBrowserGlobalErrorListeners(),
14
+ provideRouter(routes),
15
+ provideDynamicComponents(
16
+ {
17
+ 'text-field': TextFieldComponent,
18
+ 'select-field': SelectFieldComponent,
19
+ 'section-heading': SectionHeadingComponent,
20
+ },
21
+ 'editor'
22
+ ),
23
+ provideDynamicComponents(
24
+ {
25
+ 'text-field': SearchTextFieldComponent,
26
+ },
27
+ 'search'
28
+ ),
29
+ ],
30
+ };
@@ -0,0 +1,41 @@
1
+ <div class="page">
2
+ <header>
3
+ <h1>&#64;dotjem/angular-dynamic-components</h1>
4
+ <p>Consumer-driven rendering with component/config entries and record-based model data.</p>
5
+ </header>
6
+
7
+ <main>
8
+ <section class="panel">
9
+ <h2>Editor form registry</h2>
10
+ @for (entry of editorConfigurations; track $index) {
11
+ <dx-dynamic-component-host
12
+ [component]="entry.type"
13
+ registry="editor"
14
+ [data]="entry.field ? editorData[entry.field] : undefined"
15
+ [config]="entry.config"
16
+ (dataChange)="handleEditorDataChange(entry.field, $event)"
17
+ />
18
+ }
19
+ </section>
20
+
21
+ <section class="panel">
22
+ <h2>Search form registry</h2>
23
+ @for (entry of searchConfigurations; track $index) {
24
+ <dx-dynamic-component-host
25
+ [component]="entry.type"
26
+ registry="search"
27
+ [data]="entry.field ? searchData[entry.field] : undefined"
28
+ [config]="entry.config"
29
+ (dataChange)="handleSearchDataChange(entry.field, $event)"
30
+ />
31
+ }
32
+ </section>
33
+ </main>
34
+
35
+ <footer>
36
+ <p>Configuration JSON:</p>
37
+ <pre>{{ configurationJson }}</pre>
38
+ <p>Data JSON:</p>
39
+ <pre>{{ dataJson }}</pre>
40
+ </footer>
41
+ </div>
@@ -0,0 +1,3 @@
1
+ import { Routes } from '@angular/router';
2
+
3
+ export const routes: Routes = [];
File without changes
@@ -0,0 +1,27 @@
1
+ import { TestBed } from '@angular/core/testing';
2
+ import { App } from './app';
3
+ import { appConfig } from './app.config';
4
+
5
+ describe('App', () => {
6
+ beforeEach(async () => {
7
+ await TestBed.configureTestingModule({
8
+ imports: [App],
9
+ providers: [...appConfig.providers],
10
+ }).compileComponents();
11
+ });
12
+
13
+ it('should create the app', () => {
14
+ const fixture = TestBed.createComponent(App);
15
+ const app = fixture.componentInstance;
16
+ expect(app).toBeTruthy();
17
+ });
18
+
19
+ it('should render the library name in the heading', async () => {
20
+ const fixture = TestBed.createComponent(App);
21
+ await fixture.whenStable();
22
+ const compiled = fixture.nativeElement as HTMLElement;
23
+ expect(compiled.querySelector('h1')?.textContent).toContain(
24
+ '@dotjem/angular-dynamic-components'
25
+ );
26
+ });
27
+ });