From 0ec1365ec8f6a5694bf641c0588d3b20bd475d5c Mon Sep 17 00:00:00 2001
From: ievgenii <belinef@gmail.com>
Date: Mon, 3 Jul 2023 14:06:08 +0300
Subject: [PATCH] Tested difference between MFE component and Regular usage.

---
 .../package.json                              |  2 +-
 .../list-user/list-user.component.html        |  8 ++-
 .../list-user/list-user.component.ts          | 12 +++-
 .../federated/federated.component.ts          | 27 ++++++++-
 .../shell/components/home/home.component.html | 16 +++++-
 .../shell/components/home/home.component.ts   |  7 +++
 .../list-user/list-user.component.css         |  0
 .../list-user/list-user.component.html        | 24 ++++++++
 .../list-user/list-user.component.spec.ts     | 55 +++++++++++++++++++
 .../list-user/list-user.component.ts          | 43 +++++++++++++++
 .../mdmf-shell/src/app/shell/shell.module.ts  |  3 +-
 11 files changed, 187 insertions(+), 10 deletions(-)
 create mode 100644 angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/list-user/list-user.component.css
 create mode 100644 angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/list-user/list-user.component.html
 create mode 100644 angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/list-user/list-user.component.spec.ts
 create mode 100644 angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/list-user/list-user.component.ts

diff --git a/angular15-microfrontends-lazy-components/package.json b/angular15-microfrontends-lazy-components/package.json
index a39ba8cadab..a3cace4ea2a 100644
--- a/angular15-microfrontends-lazy-components/package.json
+++ b/angular15-microfrontends-lazy-components/package.json
@@ -11,7 +11,7 @@
     "start:profile": "ng serve mdmf-profile",
     "build:shared": "ng build mdmf-shared",
     "build:shell": "ng build mdmf-shell",
-    "build:profile": "ng build mdmf-profile --prod",
+    "build:profile": "ng build mdmf-profile",
     "test": "ng test mdmf-shared & ng test mdmf-profile & ng test mdmf-shell",
     "lint": "ng lint",
     "e2e": "ng e2e mdmf-profile & ng e2e mdmf-shell",
diff --git a/angular15-microfrontends-lazy-components/projects/mdmf-profile/src/app/profile/components/list-user/list-user.component.html b/angular15-microfrontends-lazy-components/projects/mdmf-profile/src/app/profile/components/list-user/list-user.component.html
index 6b0b085c195..f7c594b21d0 100644
--- a/angular15-microfrontends-lazy-components/projects/mdmf-profile/src/app/profile/components/list-user/list-user.component.html
+++ b/angular15-microfrontends-lazy-components/projects/mdmf-profile/src/app/profile/components/list-user/list-user.component.html
@@ -1,5 +1,7 @@
 <br />
 <h2>List users from the shared application state</h2>
+<h1>{{ label }}</h1>
+<h1>{{ foo }}</h1>
 <div *ngIf="users">
   <table class="table table-striped">
     <thead class="bg-primary text-white">
@@ -13,10 +15,10 @@ <h2>List users from the shared application state</h2>
       <tr *ngFor="let user of users | async">
         <td>{{ user.name }}</td>
         <td>{{ user.email }}</td>
-        <td> 
+        <td>
           <button (click)="removeUser(user)" class="btn btn-danger">Remove User</button>
-        </td>        
+        </td>
       </tr>
     </tbody>
   </table>
-</div>
\ No newline at end of file
+</div>
diff --git a/angular15-microfrontends-lazy-components/projects/mdmf-profile/src/app/profile/components/list-user/list-user.component.ts b/angular15-microfrontends-lazy-components/projects/mdmf-profile/src/app/profile/components/list-user/list-user.component.ts
index 4a74121b49a..46dad4caa57 100644
--- a/angular15-microfrontends-lazy-components/projects/mdmf-profile/src/app/profile/components/list-user/list-user.component.ts
+++ b/angular15-microfrontends-lazy-components/projects/mdmf-profile/src/app/profile/components/list-user/list-user.component.ts
@@ -1,4 +1,8 @@
-import { Component, OnInit } from '@angular/core';
+import {
+  Component,
+  Input,
+  OnInit,
+} from '@angular/core';
 import { Select, Store } from '@ngxs/store';
 import { RemoveUser } from 'projects/mdmf-shared/src/lib/app-state/actions/user.action';
 import { User } from 'projects/mdmf-shared/src/lib/app-state/models/User';
@@ -14,7 +18,11 @@ import { Observable } from 'rxjs';
 export class ListUserComponent implements OnInit {
   @Select(UserState.getUsers) users: Observable<User[]>;
 
-  constructor(private store: Store) {}
+  @Input() label = '';
+  @Input() foo = '';
+  constructor(private store: Store) {
+    console.log('Federated component Created');
+  }
 
   ngOnInit(): void {}
 
diff --git a/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/federated/federated.component.ts b/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/federated/federated.component.ts
index 0dc7d3f00d5..5b9b332efce 100644
--- a/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/federated/federated.component.ts
+++ b/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/federated/federated.component.ts
@@ -8,6 +8,7 @@ import {
   ɵcreateInjector,
 } from '@angular/core';
 import { loadRemoteModule } from '../../../utils/federation-utils';
+import { ListUserComponent } from '../list-user/list-user.component';
 
 @Component({
   selector: 'federated-component',
@@ -21,6 +22,16 @@ export class FederatedComponent implements OnInit {
   @Input() remoteName: string;
   @Input() exposedModule: string;
   @Input() componentName: string;
+  @Input() set props(props: Record<string, any>) {
+    if (this.componentRef) {
+      this.updateComponentProps(props);
+    }
+
+    this._props = props;
+  };
+
+  private componentRef = null;
+  private _props = null;
 
   constructor(private injector: Injector) {}
   ngOnInit(): void {
@@ -29,10 +40,24 @@ export class FederatedComponent implements OnInit {
       remoteName: this.remoteName,
       exposedModule: this.exposedModule,
     }).then(federated => {
-      const { instance } = this.federatedComponent.createComponent(
+      const componentRef = this.federatedComponent.createComponent(
         federated[this.exposedModule].exports.find(e => e.ɵcmp?.exportAs[0] === this.componentName),
         { injector: ɵcreateInjector(federated[this.exposedModule], this.injector) },
       );
+
+      this.componentRef = componentRef;
+
+      if (this._props) {
+        this.updateComponentProps(this._props);
+      }
     });
   }
+
+  private updateComponentProps(props: Record<string, any>) {
+    if (props && this.componentRef) {
+      Object.entries(this._props).forEach(([key, value]) => {
+        this.componentRef.setInput(key, value);
+      });
+    }
+  }
 }
diff --git a/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/home/home.component.html b/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/home/home.component.html
index 8688e646201..26228938bf8 100644
--- a/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/home/home.component.html
+++ b/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/home/home.component.html
@@ -1,10 +1,22 @@
 <div class="container">
-  <h2>Microfrontend Shell</h2>
+  <button (click)="someEvent()">Microfrontend Shell</button>
   <p>Welcome to the Angular 15 Microfrontend demo using Webpack 5 Module Federation</p>
   <p>This component is part of the shell application, the Profile component that is linked from the `Profile` link at
     the top is a Microfrontend that is remotely loaded into the application. Check the network settings to see the
     remote being loaded.</p>
     <br />
 
-    <federated-component remoteEntry="http://localhost:4201/remoteEntry.js" remoteName="profile" exposedModule="ProfileModule" componentName="ListUserComponent"></federated-component>
+    Federated Component
+    <federated-component remoteEntry="http://localhost:4201/remoteEntry.js"
+                         remoteName="profile"
+                         exposedModule="ProfileModule"
+                         componentName="ListUserComponent"
+                         [props]="{ label: federatedLabel }"
+    ></federated-component>
+</div>
+
+<div class="container">
+  Regular Component
+  <shell-profile-list-user [label]="'Regular Label 1'" foo="foo"></shell-profile-list-user>
+  <shell-profile-list-user [label]="federatedLabel" foo="foo"></shell-profile-list-user>
 </div>
diff --git a/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/home/home.component.ts b/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/home/home.component.ts
index 796fdc614e5..c9321d79fee 100644
--- a/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/home/home.component.ts
+++ b/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/home/home.component.ts
@@ -6,6 +6,13 @@ import { Component, OnInit } from '@angular/core';
   styleUrls: ['./home.component.scss'],
 })
 export class HomeComponent implements OnInit {
+  federatedLabel = 'Federated Label';
+  counter = 0;
   constructor() {}
   ngOnInit(): void {}
+
+  someEvent() {
+    this.counter += 1;
+    this.federatedLabel = 'Federated Label' + this.counter;
+  }
 }
diff --git a/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/list-user/list-user.component.css b/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/list-user/list-user.component.css
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/list-user/list-user.component.html b/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/list-user/list-user.component.html
new file mode 100644
index 00000000000..7aff26cef80
--- /dev/null
+++ b/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/list-user/list-user.component.html
@@ -0,0 +1,24 @@
+<br />
+<h1>{{ label }}</h1>
+<h1>{{ foo }}</h1>
+<h2>List users from the shared application state</h2>
+<div *ngIf="users">
+  <table class="table table-striped">
+    <thead class="bg-primary text-white">
+      <tr>
+        <th>Name</th>
+        <th>Email</th>
+        <th>Action</th>
+      </tr>
+    </thead>
+    <tbody>
+      <tr *ngFor="let user of users | async">
+        <td>{{ user.name }}</td>
+        <td>{{ user.email }}</td>
+        <td>
+          <button (click)="removeUser(user)" class="btn btn-danger">Remove User</button>
+        </td>
+      </tr>
+    </tbody>
+  </table>
+</div>
diff --git a/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/list-user/list-user.component.spec.ts b/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/list-user/list-user.component.spec.ts
new file mode 100644
index 00000000000..04b9d12b442
--- /dev/null
+++ b/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/list-user/list-user.component.spec.ts
@@ -0,0 +1,55 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { NgxsModule } from '@ngxs/store';
+import { ProfileComponent } from 'projects/mdmf-profile/src/app/profile/components/profile/profile.component';
+import { User } from 'projects/mdmf-shared/src/lib/app-state/models/User';
+import { UserState } from 'projects/mdmf-shared/src/lib/app-state/state/user.state';
+import { MdmfSharedModule } from 'projects/mdmf-shared/src/lib/modules/mdmf-shared.module';
+import { ListUserComponent } from './list-user.component';
+
+describe('ListUserShellComponent', () => {
+  let component: ListUserComponent;
+  let fixture: ComponentFixture<ListUserComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [
+        ReactiveFormsModule,
+        FormsModule,
+        MdmfSharedModule,
+        NgxsModule.forRoot([UserState]),
+      ],
+      declarations: [ListUserComponent],
+    }).compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ListUserComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create the component', () => {
+    expect(component).toBeTruthy();
+  });
+
+  it('should render h2 element', () => {
+    const element = fixture.debugElement.nativeElement.querySelector('h2');
+    expect(element.textContent).toContain('List users from the shared application state');
+  });
+
+  it('should remove an User from the store', () => {
+    const user: User = { name: 'Mr. A', email: 'a@company.com' };
+
+    // add User into the store
+    const profileComponent = TestBed.createComponent(ProfileComponent).componentInstance;
+    profileComponent.addUser(user.name, user.email);
+    expect(
+      component.getUsers().filter(u => u.name === user.name && u.email === user.email)[0],
+    ).toEqual(user);
+
+    // remove the User from the store
+    component.removeUser(user);
+    expect(component.getUsers().length).toEqual(0);
+  });
+});
diff --git a/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/list-user/list-user.component.ts b/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/list-user/list-user.component.ts
new file mode 100644
index 00000000000..229b7800faa
--- /dev/null
+++ b/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/components/list-user/list-user.component.ts
@@ -0,0 +1,43 @@
+import {
+  Component,
+  Input,
+  OnInit,
+} from '@angular/core';
+import { Select, Store } from '@ngxs/store';
+import { RemoveUser } from 'projects/mdmf-shared/src/lib/app-state/actions/user.action';
+import { User } from 'projects/mdmf-shared/src/lib/app-state/models/User';
+import { UserState } from 'projects/mdmf-shared/src/lib/app-state/state/user.state';
+import { Observable } from 'rxjs';
+
+@Component({
+  selector: 'shell-profile-list-user',
+  templateUrl: './list-user.component.html',
+  styleUrls: ['./list-user.component.css'],
+})
+export class ListUserComponent implements OnInit {
+  @Select(UserState.getUsers) users: Observable<User[]>;
+
+  @Input() label = '';
+  @Input() foo = '';
+
+  constructor(private store: Store) {
+    console.log('Regular component Created');
+  }
+
+  ngOnInit(): void {}
+
+  /**
+   * Handle the remove user when the "Remove User" button is clicked
+   * @param user: the user info
+   */
+  removeUser(user: User): void {
+    this.store.dispatch(new RemoveUser(user));
+  }
+
+  /**
+   * Get the users for unit testing purposes
+   */
+  getUsers(): User[] {
+    return this.store.selectSnapshot<User[]>(state => state.users.users);
+  }
+}
diff --git a/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/shell.module.ts b/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/shell.module.ts
index 31d95894e97..b6f9ed2d840 100644
--- a/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/shell.module.ts
+++ b/angular15-microfrontends-lazy-components/projects/mdmf-shell/src/app/shell/shell.module.ts
@@ -5,9 +5,10 @@ import { ProfileRoutingModule } from './shell-routing.module';
 import { HomeComponent } from './components/home/home.component';
 import { FederatedComponent } from './components/federated/federated.component';
 import { MdmfSharedModule } from 'projects/mdmf-shared/src/lib/modules/mdmf-shared.module';
+import { ListUserComponent } from './components/list-user/list-user.component';
 
 @NgModule({
-  declarations: [HomeComponent, FederatedComponent],
+  declarations: [HomeComponent, FederatedComponent, ListUserComponent],
   imports: [CommonModule, ProfileRoutingModule, FormsModule, ReactiveFormsModule, MdmfSharedModule],
 })
 export class ShellModule {}