|
1 | | -import { state } from "@rx-state/core" |
| 1 | +import { |
| 2 | + EmptyObservableError, |
| 3 | + NoSubscribersError, |
| 4 | + sinkSuspense, |
| 5 | + state, |
| 6 | + SUSPENSE, |
| 7 | +} from "@rx-state/core" |
2 | 8 | import { act, render, screen } from "@testing-library/react" |
3 | 9 | import React, { StrictMode, useEffect, useState } from "react" |
4 | | -import { defer, EMPTY, NEVER, Observable, of, startWith } from "rxjs" |
| 10 | +import { defer, EMPTY, NEVER, Observable, of, startWith, Subject } from "rxjs" |
5 | 11 | import { bind, RemoveSubscribe, Subscribe as OriginalSubscribe } from "./" |
6 | 12 | import { TestErrorBoundary } from "./test-helpers/TestErrorBoundary" |
7 | 13 | import { useStateObservable } from "./useStateObservable" |
@@ -160,6 +166,23 @@ describe("Subscribe", () => { |
160 | 166 | expect(getByTestId("value").textContent).toBe("2") |
161 | 167 | instanceTwoSubs.unsubscribe() |
162 | 168 | }) |
| 169 | + |
| 170 | + it("lifts the effects of the source$ prop", () => { |
| 171 | + const subject$ = new Subject<number | SUSPENSE>() |
| 172 | + const test$ = state(subject$.pipe(sinkSuspense())) |
| 173 | + |
| 174 | + const { unmount } = render(<Subscribe source$={test$} />) |
| 175 | + |
| 176 | + expect(test$.getRefCount()).toBe(1) |
| 177 | + |
| 178 | + act(() => subject$.next(SUSPENSE)) |
| 179 | + expect(test$.getRefCount()).toBe(1) |
| 180 | + |
| 181 | + act(() => subject$.next(1)) |
| 182 | + expect(test$.getRefCount()).toBe(1) |
| 183 | + |
| 184 | + unmount() |
| 185 | + }) |
163 | 186 | }) |
164 | 187 | describe("Subscribe without source$", () => { |
165 | 188 | it("subscribes to the provided observable and remains subscribed until it's unmounted", () => { |
@@ -337,6 +360,76 @@ describe("Subscribe", () => { |
337 | 360 | ) |
338 | 361 | unmount() |
339 | 362 | }) |
| 363 | + |
| 364 | + it("propagates the EmptyObservable error if a stream completes synchronously", async () => { |
| 365 | + const globalErrors = jest.spyOn(console, "error") |
| 366 | + globalErrors.mockImplementation() |
| 367 | + |
| 368 | + const [useEmpty] = bind(() => EMPTY) |
| 369 | + |
| 370 | + const ErrorComponent = () => { |
| 371 | + useEmpty() |
| 372 | + return null |
| 373 | + } |
| 374 | + |
| 375 | + const errorCallback = jest.fn() |
| 376 | + const { unmount } = render( |
| 377 | + <TestErrorBoundary onError={errorCallback}> |
| 378 | + <Subscribe fallback={<div>Loading...</div>}> |
| 379 | + <ErrorComponent /> |
| 380 | + </Subscribe> |
| 381 | + </TestErrorBoundary>, |
| 382 | + ) |
| 383 | + |
| 384 | + // Can't have NoSubscribersError |
| 385 | + // Can't have "Cannot update component (`%s`) while rendering a different component" |
| 386 | + globalErrors.mock.calls.forEach(([errorMessage]) => { |
| 387 | + expect(errorMessage).not.toContain(NoSubscribersError.name) |
| 388 | + expect(errorMessage).not.toContain( |
| 389 | + "Cannot update a component (`%s`) while rendering a different component", |
| 390 | + ) |
| 391 | + }) |
| 392 | + globalErrors.mockRestore() |
| 393 | + |
| 394 | + // Must have EmptyObservableError |
| 395 | + expect(errorCallback.mock.calls.length).toBe(1) |
| 396 | + expect(errorCallback.mock.calls[0][0]).toBeInstanceOf( |
| 397 | + EmptyObservableError, |
| 398 | + ) |
| 399 | + |
| 400 | + unmount() |
| 401 | + }) |
| 402 | + |
| 403 | + it("lifts the effects of observables passed through context", () => { |
| 404 | + const subject$ = new Subject<number | SUSPENSE>() |
| 405 | + let innerSubs = 0 |
| 406 | + const test$ = state( |
| 407 | + defer(() => { |
| 408 | + innerSubs++ |
| 409 | + return subject$ |
| 410 | + }).pipe(sinkSuspense()), |
| 411 | + ) |
| 412 | + |
| 413 | + const Child = () => <>{useStateObservable(test$)}</> |
| 414 | + |
| 415 | + const { unmount } = render( |
| 416 | + <Subscribe> |
| 417 | + <Child /> |
| 418 | + </Subscribe>, |
| 419 | + ) |
| 420 | + |
| 421 | + expect(test$.getRefCount()).toBe(1) |
| 422 | + |
| 423 | + act(() => subject$.next(SUSPENSE)) |
| 424 | + expect(test$.getRefCount()).toBe(1) |
| 425 | + |
| 426 | + act(() => subject$.next(1)) |
| 427 | + expect(test$.getRefCount()).toBe(1) |
| 428 | + |
| 429 | + expect(innerSubs).toBe(1) |
| 430 | + |
| 431 | + unmount() |
| 432 | + }) |
340 | 433 | }) |
341 | 434 | }) |
342 | 435 |
|
|
0 commit comments