Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ jobs:
strategy:
fail-fast: false
matrix:
node: [18, 22] # Min and max supported Node versions
node: [18, 22, 24] # Min and max officially supported Node versions + next max
platform: [linux-x64, linux-arm, macos-x64, macos-arm, windows-x64]
include:
- platform: linux-x64
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/conventions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22

- name: Get NPM cache directory
id: npm-cache-dir
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22

- name: Get NPM cache directory
id: npm-cache-dir
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22

- name: Get NPM cache directory
id: npm-cache-dir
Expand Down Expand Up @@ -213,7 +213,7 @@ jobs:
strategy:
fail-fast: false
matrix:
node: [18, 22] # Min and max supported Node versions
node: [18, 22, 24] # Min and max officially supported Node versions + next max
platform: [linux-x64, linux-arm, macos-x64, macos-arm, windows-x64]
sample: [hello-world, fetch-esm, hello-world-mtls]
server: [cli, cloud]
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/stress.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22

- name: Get NPM cache directory
id: npm-cache-dir
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ packages/*/package-lock.json
# One test creates persisted SQLite DBs; they should normally be deleted automatically,
# but may be left behind in some error scenarios.
packages/test/temporal-db-*.sqlite
.DS_Store
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ See [sdk-structure.md](./docs/sdk-structure.md)

### Environment setup

The TS SDK can be executed on 18, 20 or 22. However, we recommend using Node 22 for SDK development.
TS SDK is officially supported on Node 18, 20, 22, or 24. However, we recommend using the
[Active LTS](https://nodejs.org/en/about/previous-releases#nodejs-releases) for SDK development.
For easier testing during development you may want to use a version manager, such as
[fnm](https://github.com/Schniz/fnm) or [nvm](https://github.com/nvm-sh/nvm/blob/master/README.md).

Expand Down
3 changes: 2 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 16 additions & 1 deletion packages/test/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as net from 'net';
import path from 'path';
import * as grpc from '@grpc/grpc-js';
import asyncRetry from 'async-retry';
import ava, { TestFn } from 'ava';
import ava, { TestFn, ExecutionContext } from 'ava';
import StackUtils from 'stack-utils';
import { v4 as uuid4 } from 'uuid';
import { Client, Connection } from '@temporalio/client';
Expand Down Expand Up @@ -98,6 +98,21 @@ export function cleanStackTrace(ostack: string): string {
return normalizedStack ? `${firstLine}\n${normalizedStack}` : firstLine;
}

/**
* Compare stack traces using $CLASS keyword to match any inconsistent identifiers
*
* As of Node 24.6.0 type names are now present on source mapped stack traces which leads
* to different stack traces depending on Node version.
* See [f33e0fcc83954f728fcfd2ef6ae59435bc4af059](https://github.com/nodejs/node/commit/f33e0fcc83954f728fcfd2ef6ae59435bc4af059)
*/
export function compareStackTraceIdentifiers<T>(t: ExecutionContext<T>, actual: string, expected: string): void {
const escapedTrace = expected
.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
.replace(/-/g, '\\x2d')
.replaceAll('\\$CLASS', '(?:[A-Za-z]+)');
t.regex(actual, RegExp(`^${escapedTrace}$`));
}

function noopTest(): void {
// eslint: this function body is empty and it's okay.
}
Expand Down
16 changes: 9 additions & 7 deletions packages/test/src/test-integration-split-one.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import {
} from '@temporalio/workflow';
import { configurableHelpers, createTestWorkflowBundle } from './helpers-integration';
import * as activities from './activities';
import { cleanOptionalStackTrace, u8, Worker } from './helpers';
import { cleanOptionalStackTrace, compareStackTraceIdentifiers, u8, Worker } from './helpers';
import { configMacro, makeTestFn } from './helpers-integration-multi-codec';
import * as workflows from './workflows';

Expand Down Expand Up @@ -204,11 +204,12 @@ test.serial('activity-failure with ApplicationFailure', configMacro, async (t, c
t.is(err.cause.cause.message, 'Fail me');
t.is(err.cause.cause.type, 'Error');
t.deepEqual(err.cause.cause.details, ['details', 123, false]);
t.is(
cleanOptionalStackTrace(err.cause.cause.stack),
compareStackTraceIdentifiers(
t,
cleanOptionalStackTrace(err.cause.cause.stack)!,
dedent`
ApplicationFailure: Fail me
at Function.nonRetryable (common/src/failure.ts)
at $CLASS.nonRetryable (common/src/failure.ts)
at throwAnError (test/src/activities/index.ts)
`
);
Expand Down Expand Up @@ -258,11 +259,12 @@ test.serial('child-workflow-failure', configMacro, async (t, config) => {
return t.fail('Expected err.cause.cause to be an instance of ApplicationFailure');
}
t.is(err.cause.cause.message, 'failure');
t.is(
cleanOptionalStackTrace(err.cause.cause.stack),
compareStackTraceIdentifiers(
t,
cleanOptionalStackTrace(err.cause.cause.stack)!,
dedent`
ApplicationFailure: failure
at Function.nonRetryable (common/src/failure.ts)
at $CLASS.nonRetryable (common/src/failure.ts)
at throwAsync (test/src/workflows/throw-async.ts)
`
);
Expand Down
11 changes: 8 additions & 3 deletions packages/test/src/test-integration-split-three.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { configMacro, makeTestFn } from './helpers-integration-multi-codec';
import { configurableHelpers } from './helpers-integration';
import { withZeroesHTTPServer } from './zeroes-http-server';
import * as activities from './activities';
import { approximatelyEqual, cleanOptionalStackTrace } from './helpers';
import { approximatelyEqual, cleanOptionalStackTrace, compareStackTraceIdentifiers } from './helpers';
import * as workflows from './workflows';

const test = makeTestFn(() => bundleWorkflowCode({ workflowsPath: require.resolve('./workflows') }));
Expand Down Expand Up @@ -48,7 +48,6 @@ if ('promiseHooks' in v8) {
t.true(
stack1.endsWith(
`
at Function.all (<anonymous>)
at stackTracer (test/src/workflows/stack-tracer.ts)

at stackTracer (test/src/workflows/stack-tracer.ts)
Expand Down Expand Up @@ -91,11 +90,17 @@ if ('promiseHooks' in v8) {
}));
t.is(enhancedStack.sdk.name, 'typescript');
t.is(enhancedStack.sdk.version, pkg.version); // Expect workflow and worker versions to match
{
const functionName = stacks[0]!.locations[0]!.function_name!;
delete stacks[0]!.locations[0]!.function_name;
compareStackTraceIdentifiers(t, functionName, '$CLASS.all');
}
t.deepEqual(stacks, [
{
locations: [
{
function_name: 'Function.all',
// Checked sperately above to handle Node 24 behavior change with respect to identifiers in stack traces
// function_name: 'Function.all',
internal_code: false,
},
{
Expand Down
9 changes: 5 additions & 4 deletions packages/test/src/test-interceptors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { WorkflowClient, WorkflowFailedError } from '@temporalio/client';
import { ApplicationFailure, TerminatedFailure } from '@temporalio/common';
import { DefaultLogger, Runtime } from '@temporalio/worker';
import { defaultPayloadConverter, WorkflowInfo } from '@temporalio/workflow';
import { cleanOptionalStackTrace, RUN_INTEGRATION_TESTS, Worker } from './helpers';
import { cleanOptionalStackTrace, compareStackTraceIdentifiers, RUN_INTEGRATION_TESTS, Worker } from './helpers';
import { defaultOptions } from './mock-native-worker';
import {
continueAsNewToDifferentWorkflow,
Expand Down Expand Up @@ -241,11 +241,12 @@ if (RUN_INTEGRATION_TESTS) {
return;
}
t.deepEqual(err.cause.message, 'Expected anything other than 1');
t.is(
cleanOptionalStackTrace(err.cause.stack),
compareStackTraceIdentifiers(
t,
cleanOptionalStackTrace(err.cause.stack)!,
dedent`
ApplicationFailure: Expected anything other than 1
at Function.nonRetryable (common/src/failure.ts)
at $CLASS.nonRetryable (common/src/failure.ts)
at Object.continueAsNew (test/src/workflows/interceptor-example.ts)
at workflow/src/workflow.ts
at continueAsNewToDifferentWorkflow (test/src/workflows/continue-as-new-to-different-workflow.ts)
Expand Down
12 changes: 7 additions & 5 deletions packages/test/src/test-nexus-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
convertWorkflowEventLinkToNexusLink,
convertNexusLinkToWorkflowEventLink,
} from '@temporalio/nexus/lib/link-converter';
import { cleanStackTrace, getRandomPort } from './helpers';
import { cleanStackTrace, compareStackTraceIdentifiers, getRandomPort } from './helpers';

export interface Context {
httpPort: number;
Expand Down Expand Up @@ -314,10 +314,11 @@ test('start Operation Handler errors', async (t) => {
});
t.true(err instanceof ApplicationFailure);
t.is(err.message, '');
t.is(
compareStackTraceIdentifiers(
t,
cleanStackTrace(err.stack!),
`ApplicationFailure: deliberate failure
at Function.create (common/src/failure.ts)
at $CLASS.create (common/src/failure.ts)
at op (test/src/test-nexus-handler.ts)
at Object.start (nexus-rpc/src/handler/operation-handler.ts)
at ServiceRegistry.start (nexus-rpc/src/handler/service-registry.ts)`
Expand Down Expand Up @@ -460,10 +461,11 @@ test('cancel Operation Handler errors', async (t) => {
});
t.true(err instanceof ApplicationFailure);
t.is(err.message, '');
t.is(
compareStackTraceIdentifiers(
t,
cleanStackTrace(err.stack!),
`ApplicationFailure: deliberate failure
at Function.create (common/src/failure.ts)
at $CLASS.create (common/src/failure.ts)
at Object.cancel (test/src/test-nexus-handler.ts)
at ServiceRegistry.cancel (nexus-rpc/src/handler/service-registry.ts)`
);
Expand Down
Loading
Loading