Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing a signal #277

Open
sbitproz opened this issue Jul 20, 2022 · 1 comment
Open

Testing a signal #277

sbitproz opened this issue Jul 20, 2022 · 1 comment

Comments

@sbitproz
Copy link

Overview

I'm trying to test a signal which is exported from a JS module. The problem is that between tests it's changed and the tests become interdependent.

Recreation

export const [launchedPressed$, pressLaunch] = createSignal<Launch>();

Which has the following binding

export const [useLaunchRocket, launchRocket$] = bind(
  launchedPressed$.pipe(
    switchMap(({ delaySeconds, url, status, timeoutSeconds }) => {
      return status === LaunchStatus.WORKING
        ? of(LaunchStatus.ABORTED)
        : ajax.getJSON(`${url}${delaySeconds}`).pipe(
            map(() => LaunchStatus.STANDBY),
            timeoutWhen(!!timeoutSeconds, (timeoutSeconds ?? 10) * 1000),
            catchError(() => of(LaunchStatus.ABORTED)),
          );
    }),
    map((status) => ({ status })),
    startWith({ status: LaunchStatus.STANDBY }),
  ),
);

Because the signal is exported from this module it's akin to a global variable and the value is changed between tests within the test runner. This makes the values less predictable and the tests more flaky and interdependent.

it("should emit aborted when status is working and pressLaunch is called", () => {
    testScheduler.run(async (helpers) => {
      const { cold, expectObservable } = helpers;
      const payloadA: { a: Launch } = {
        a: {
          delaySeconds: 1,
          status: "working",
          url: "www.google.com",
          timeoutSeconds: 2,
        },
      };
      const expectedA = { a: { status: "standby" }, b: { status: "aborted" } };

      const source$ = cold("a", payloadA).pipe(tap((a) => pressLaunch(a)));

      expectObservable(source$).toBe("a", payloadA);
      expectObservable(launchRocket$).toBe("(ab)", expectedA);
    });
  });

  it("should abort when the delay exceeds the timeout", () => {
    (ajax.getJSON as jest.Mock).mockImplementation(() => of("test").pipe(delay(3000)));

    testScheduler.run(async (helpers) => {
      const { cold, expectObservable } = helpers;
      const payloadA: { a: Launch } = {
        a: {
          delaySeconds: 3,
          status: "standby",
          url: "www.google.com",
          timeoutSeconds: 2,
        },
      };
      const expectedA = { a: { status: "standby" }, b: { status: "aborted" } };

      const source$ = cold("a", payloadA).pipe(tap((a) => pressLaunch(a)));

      expectObservable(source$).toBe("a", payloadA);
      expectObservable(launchRocket$).toBe("a 2000ms b", expectedA);
    });
  })

Is my analysis correct?

What's the best approach to testing signals?

Are there any examples on the https://react-rxjs.org/ ?

@bruceharris
Copy link

@sbitproz it seems to me that your question may be more about testing observation chains than about testing signals per se. Regardless, this article https://weareadaptive.com/2024/01/09/unit-testing-rxjs-observables-a-practical-guide/ provides guidance on how to test code like that in the example here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants