TestWorkflowEnvironment.createTimeSkipping() results in a test failure with no error message

I’m trying to test a workflow that waits for either a signal/trigger, or 10 minutes, whichever comes first. Stripped down a little bit, it looks like this:

import { proxyActivities, defineSignal, sleep, Trigger, setHandler } from '@temporalio/workflow';

import type * as activities from './activities';

const { sendSlackNotification } = proxyActivities<typeof activities>({
  startToCloseTimeout: '1 minute',
});

export const completeSignal = defineSignal('completeConnection');

export async function waitForConnectionCompletion(id: string): Promise<boolean> {
  const completeTrigger = new Trigger<boolean>();
  setHandler(completeSignal, () => completeTrigger.resolve(true));
  const connectionCompleted = await Promise.race([completeTrigger, sleep('10 minutes')]);
  if (connectionCompleted) {
    return true;
  } else {
    await sendSlackNotification(id);
    return false;
  }
}

The entirety of my test file looks like this:

import { Runtime, DefaultLogger, Worker, LogEntry } from '@temporalio/worker';
import { WorkflowCoverage } from '@temporalio/nyc-test-coverage';
import { TestWorkflowEnvironment } from '@temporalio/testing';
import { v4 as uuid } from 'uuid';

import * as activities from '../activities';
import { waitForConnectionCompletion } from '../index';

const workflowCoverage = new WorkflowCoverage();
let testEnv: TestWorkflowEnvironment;

const mockActivities: Partial<typeof activities> = {
  sendSlackNotification: () => {
    return Promise.resolve({ success: true, metadata: {} });
  },
};

describe('waitForConnectionCompletionWorkflow', () => {
  beforeAll(() => {
    // Use console.log instead of console.error to avoid red output
    // Filter INFO log messages for clearer test output
    Runtime.install({
      logger: new DefaultLogger('INFO', (entry: LogEntry) =>
        // eslint-disable-next-line no-console
        console.log(`[${entry.level}]`, entry.message)
      ),
    });
  });

  describe('if the connection does not complete within 10 minutes', () => {
    beforeAll(async () => {
      testEnv = await TestWorkflowEnvironment.createTimeSkipping();
    });

    afterAll(async () => {
      await testEnv?.teardown();
    });

    afterAll(() => {
      jest.clearAllMocks();
      workflowCoverage.mergeIntoGlobalCoverage();
    });

    it('returns a completed status and connection_completed as false', async () => {
      const { client, nativeConnection } = testEnv as TestWorkflowEnvironment;
      const worker = await Worker.create(
        workflowCoverage.augmentWorkerOptions({
          connection: nativeConnection,
          taskQueue: 'test',
          workflowsPath: require.resolve('../index'),
          activities: mockActivities,
        })
      );

      const result = await worker.runUntil(async () => {
        return await client.workflow.execute(waitForConnectionCompletion, {
          taskQueue: 'test',
          workflowId: `connecting_${uuid()}`,
          args: ['id'],
        });
      });
      expect(result).toEqual(false);
    });
  });
});

Whenever I use TestWorkflowEnvironment.createTimeSkipping(), my test output looks like this:

No discernable logs, error messages, or causes of failure.

When I switch it to use TestWorkflowEnvironment.createLocal() and insert an await testEnv.sleep('10 minutes'), that at least brings up the logs while the test runs, but the test ends up timing out (even if I set a timeout of 30 seconds - plenty of time for the test to run if the sleep in the workflow was skipped, which it does not appear to be).

Would love any ideas you have for me!

1 Like

I have the same problem. I’m finding that the promise returned by createTimeSkipping never resolves! This simple code reproduces it for me:

let testEnv: TestWorkflowEnvironment;
beforeAll(async () => {
  console.log('before');
  testEnv = await TestWorkflowEnvironment.createTimeSkipping();
  console.log('after');
});

“before” is logged, but “after” never is.

I am using Temporal packages on v1.11.2.

Update: I think part of the problem is that the Jest hook is not surfacing errors! If I add .catch(error => console.log(error)), I see this error:

[UnexpectedError: Failed to start ephemeral server: Bad CPU type in executable (os error 86)]

I’m on Mac Sequoia 15.1.