Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Testing with ngxs/store @select gives error: "SelectFactory not connected to store!"

The project is running without errors. But all the tests are failing with "SelectFactory not connected to store!". It was working before we broke the Observables out to the base class.

Can I stub the Base Class? Stub @Select? Stub the store? Use something beside @Select?

I need it to keep listening to the store observables. And it needs to extend the base class. Everything else is up in the air.

Packages:

"@angular/core": "7.2.11",
"@ngxs/store": "^3.4.3"

Component

@Component({
    selector: "app-billing-landing",
    templateUrl: "./billing-landing.component.html",
    styleUrls: ["./billing-landing.component.scss"],
    animations: [fadeInRightLeft]
})
export class BillingLandingComponent extends BillingCore implements OnInit {
    constructor(public dialog: MatDialog, public router: Router) {
        super(router, dialog);    
    }
    ....Other Methods
}

Base Component

@NgModule()
export class BillingCore {
    @Select(AccountState.getCurrentPatient) currentPatient$: Observable<ProxySwitchUser>;
    @Select(AccountState.getLoggedInUser) loggedInUser$: Observable<Patient>;

    constructor(public router: Router, public dialog: MatDialog) {

        combineLatest([this.currentPatient$, this.loggedInUser$]).subscribe(dataArray => {
            ....Do Stuff
        });
    }
    ....Other Methods
}

Test File

describe("BillingLandingComponent", () => {
    let component: BillingLandingComponent;
    let fixture: ComponentFixture<BillingLandingComponent>;
    const matDialogServiceSpy = jasmine.createSpyObj("MatDialog", ["open"]);

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            imports: [JssModule.forRoot(), RouterTestingModule, NoopAnimationsModule],
            declarations: [BillingLandingComponent],
            providers: [{ provide: MatDialog, useValue: matDialogServiceSpy }],
            schemas: [CUSTOM_ELEMENTS_SCHEMA]
        });

        fixture = TestBed.createComponent(BillingLandingComponent);
        component = fixture.componentInstance;

        Object.defineProperty(component, "currentPatient$", { writable: true });
        Object.defineProperty(component, "loggedInUser$", { writable: true });
        component.currentPatient$ = of(mockPatient as Patient);
        component.loggedInUser$ = of(mockPatient as Patient);


        fixture.detectChanges();
    }));

    it("should create", () => {
        expect(component).toBeTruthy();
    });
});
like image 263
Mardok Avatar asked Sep 02 '25 09:09

Mardok


1 Answers

I found some suggestions for this at: https://github.com/ngxs/store/issues/482

The reasoning behind this solution is that the unit-test for the component should not test Ngxs related functionality ( e.g. the @Select decorator ).

Copied the answer from there that helped me ( in case link goes stale ):

beforeEach(() => {  
   fixture = TestBed.createComponent(RequestStartAllowanceComponent);
   component = fixture.componentInstance;  
   Object.defineProperty(component, 'prop$', { writable: true });  
   component.prop$ = of('value');  
   fixture.detectChanges();  

});

So here prop$ is the component property using the select decorator:

@Select(state=>state.someStateValue) prop$: Observable;

I hope this helps.

like image 104
Eli Avatar answered Sep 04 '25 00:09

Eli