Mardok
Mardok

Reputation: 1460

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();
    });
});

Upvotes: 4

Views: 2877

Answers (1)

Eli
Eli

Reputation: 1836

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.

Upvotes: 2

Related Questions