Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to establish a websocket connection in Angular unit tests?

I'm working on an Angular (v 6.1.0) app which is communicating with a backend over a websocket. So far everything's been working fine except for the unit testing. I've created a mock backend for the purpose of testing my components but I just can't establish a connection between the mock backend and testing modules. I'm using Jasmine as an assertion library and Jest as a test runner, this is a sample test suite:

describe('RandomComponent', () => {
  let component: RandomComponent;
  let fixture: ComponentFixture<RandomComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [],
      imports: [SomeModule],
      providers: [SpecialWebSocketService, WebSocketService,
        { provide: BackendUrlService, useClass: BackendUrlMockService }
      ]
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(RandomComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create random component', () => {
      expect(component).toBeTruthy();
  });
});

BackendUrlMockService is there just to provide a URL. The single test case produces the following:

 FAIL  src/app/path/to/my/random.component.spec.ts
  RandomComponent
    ✕ should create random component (603ms)

  ● RandomComponent › should create random component

    InvalidStateError: Still in CONNECTING state.

Application works fine both with real backend and the mocked one. Testing modules work with neither. I also noticed that if I add a timeout to the test case:

it('should create random component', (done) => {
  setTimeout(() => {
    expect(component).toBeTruthy();
    done();
  }, 1000);
});

My mock backend logs a message that connection was established properly but I still get the error. Does anyone have an idea how to set up everything properly so that I could test my components?

like image 689
qwrtln Avatar asked Oct 18 '25 16:10

qwrtln


1 Answers

Based on @user184994 comment I decided to mock the websocket instead of the backend:

const mockData = {
  // some arbitrary data
};

class WebSocketServiceSpy {

  private messageSpy = new Subject<string>();
  private messageHandler = this.messageSpy.asObservable();

  createObservableSocket(url: string): Observable<string> {
    console.log(`Websocket would connect to ${url}.`);

   return new Observable(observer => {
      this.messageHandler.subscribe(() => {
        observer.next(JSON.stringify(mockData));
      });
    });
  }

  sendMessage(message: any) {
    this.messageSpy.next();
  }
}

Then, I used it in the testing module:

beforeEach(async(() => {
  TestBed.configureTestingModule({
    declarations: [],
    imports: [SomeModule],
      providers: [SpecialWebSocketService, BackendUrlService,
        { provide: WebSocketService, useClass: WebSocketServiceSpy }  
    ]
  })
    .compileComponents();
}));

And the test is finally green:

PASS  src/app/path/to/my/random.component.spec.ts
 ● Console

   console.log src/app/path/to/my/random.component.spec.ts:911
     Websocket would connect to <actual url>.
like image 52
qwrtln Avatar answered Oct 20 '25 08:10

qwrtln