Skip to content

Testing a signal #277

@sbitproz

Description

@sbitproz

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/ ?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions