Assuming we have two components, AppleComponent and BananaComponent, and we need to write test for AppleComponent.
AppleComponent
@Component({
selector: 'Apple-Component',
styleUrls: ['./apple.component.scss'],
templateUrl: './apple.component.html',
})
export class AppleComponent<T,U extends BananaComponent<T>>{
public appleA = 'appleA';
public appleB = 'appleB';
public applePurchase !: U;
}
BananaComponent
@Component({
selector: 'Banana-Component',
styleUrls: ['./banana.component.scss'],
templateUrl: './banana.component.html',
})
export abstract class BananaComponent<T> implements OnInit{
public bananaA = 'bananaA';
public bananaB = 'bananaB';
public bananaPurchase : T;
public totalPurchase: T;
}
And spec test file for AppleComponent
spec file
import { CommonModule } from '@angular/common';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import {AppleComponent} from '....';
import {BananaComponent} from '....';
describe('AppleComponent', () => {
let component: AppleComponent;
let fixture: ComponentFixture<AppleComponent>;
beforeEach(()=>{
TestBed.configureTestingModule({
declarations:[AppleComponent],
imports:[ all imports from apple.component.module.ts],
});
fixture = TestBed.createComponent(AppleComponent);
component = fixture.componentInstance;
});
it('should with defaults',() => {
expect(component.appleA).toBe('appleA','appleA has appleA as default value'); // passes
expect(component.bananaA).toBe('bananaA','bananaA has bananaA as default value'); // failes
});
});
The above code is totally fine if AppleComponent has no type, but since we have <T,U extends BananaComponent> defined in AppleComponent, so the above spec test code will not work.
Solution
// first inside the test to define a random type, then give it to AppleComponent, and BananaComponent.
type typeA = { };
type typeModel = AppleComponent<typeA, BananaComponent<typeA>>;
let component: typeModel;
let fixture: ComponentFixture<typeModel>
Explaination
What is happnening here is just the type of AppleComponent extends the BananaComponent; The purpose is to keep the type of the input value inside the AppleComponent to be identical with the type of input value inside BananaComponent.
And for a better understanding of the relationship between the types of AppleComponent and BananaComponent, here are the more detailed codes.
AppleComponent
export class AppleComponent<T,U extends BananaComponent<T>>{
public appleA = 'appleA';
public appleB = 'appleB';
public applePurchase !: U;
}
BananaComponent
export abstract class BananaComponent<T> implements OnInit{
public bananaA = 'bananaA';
public bananaB = 'bananaB';
public bananaPurchase : T;
public totalPurchase: T;
}
from the above code, we could see that
inside BananaComponent, type T is to make sure the input bananaPurchase has the same type with totalPurchase, e.g. when bananaPurchase = 1000; then the type is set to number, then the value of totalPurchase has to be a number as well, and vice versa.
same situation inside AppleComponent, because it extends the type from BananaComponent, therefore it means the applePurchase should have the same type with bananaPurchase and totalPurchase.
Assuming we have two components, AppleComponent and BananaComponent, and we need to write test for AppleComponent.
AppleComponent
BananaComponent
And spec test file for AppleComponent
spec file
The above code is totally fine if AppleComponent has no type, but since we have <T,U extends BananaComponent> defined in AppleComponent, so the above spec test code will
not work
.Solution
Explaination
What is happnening here is just the type of AppleComponent extends the BananaComponent; The purpose is to keep the type of the input value inside the AppleComponent to be identical with the type of input value inside BananaComponent.
And for a better understanding of the relationship between the types of AppleComponent and BananaComponent, here are the more detailed codes.
AppleComponent
BananaComponent
from the above code, we could see that
inside BananaComponent, type T is to make sure the input bananaPurchase has the same type with totalPurchase, e.g. when bananaPurchase = 1000; then the type is set to number, then the value of totalPurchase has to be a number as well, and vice versa.
same situation inside AppleComponent, because it extends the type from BananaComponent, therefore it means the applePurchase should have the same type with bananaPurchase and totalPurchase.
This is actually coming from a post of mine on stackoverflow
For more info, please take How to test an @Input varaible inside Angular Testing as reference