taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit ece7aabb541a58ed74b7579393572af67ef8b40c
parent d83315f0c1bdaf2048921dea936151a5330b7115
Author: Florian Dold <dold@taler.net>
Date:   Wed,  1 Jul 2026 22:48:22 +0200

make sure all tests run, delete two legacy/umaintained test files

Diffstat:
Mpackage.json | 3++-
Mpackages/anastasis-core/package.json | 4++--
Mpackages/anastasis-webui/test.mjs | 2+-
Mpackages/challenger-webui/test.mjs | 2+-
Mpackages/idb-bridge/package.json | 2+-
Mpackages/libeufin-bank-webui/test.mjs | 2+-
Mpackages/pogen/package.json | 2+-
Mpackages/taler-auditor-webui/test.mjs | 2+-
Mpackages/taler-exchange-aml-webui/test.mjs | 2+-
Mpackages/taler-exchange-kyc-webui/test.mjs | 2+-
Mpackages/taler-merchant-webui/test.mjs | 2+-
Mpackages/taler-util/package.json | 4++--
Mpackages/taler-wallet-core/package.json | 6+++---
Dpackages/taler-wallet-webextension/src/cta/Payment/Payment.test.ts | 430-------------------------------------------------------------------------------
Dpackages/taler-wallet-webextension/src/stories.test.ts | 67-------------------------------------------------------------------
Mpackages/taler-wallet-webextension/test.mjs | 2+-
Mpackages/web-util/src/index.build.ts | 4++++
17 files changed, 23 insertions(+), 515 deletions(-)

diff --git a/package.json b/package.json @@ -8,7 +8,8 @@ "lint": "pnpm --filter @gnu-taler/qa-tooling install && ./packages/qa-tooling/bin/eslint.mjs .", "i18n:source2po": "pnpm run --filter '@gnu-taler/*' i18n:source2po", "i18n:po2strings": "pnpm run --filter '@gnu-taler/*' i18n:po2strings", - "check": "pnpm run --filter '@gnu-taler/*' --if-present --sequential test" + "check": "pnpm run --filter '@gnu-taler/*' --if-present --sequential --no-bail test", + "test": "pnpm run --filter '@gnu-taler/*' --if-present --sequential --no-bail test" }, "devDependencies": { "esbuild": "^0.28.0", diff --git a/packages/anastasis-core/package.json b/packages/anastasis-core/package.json @@ -8,8 +8,8 @@ "scripts": { "compile": "tsc", "pretty": "prettier --write src", - "test": "tsc && node --test lib/*.test.js lib/**/*.test.js", - "coverage": "tsc && c8 --src src --all node --test lib/*.test.js lib/**/*.test.js", + "test": "tsc && node --test 'lib/*.test.js' 'lib/**/*.test.js'", + "coverage": "tsc && c8 --src src --all node --test 'lib/*.test.js' 'lib/**/*.test.js'", "typedoc": "pnpm dlx typedoc --out dist/typedoc ./src/", "clean": "rm -rf dist lib tsconfig.tsbuildinfo" }, diff --git a/packages/anastasis-webui/test.mjs b/packages/anastasis-webui/test.mjs @@ -17,7 +17,7 @@ import { build } from "@gnu-taler/web-util/build"; import { getFilesInDirectory } from "@gnu-taler/web-util/build"; -const allTestFiles = getFilesInDirectory("src", /\\.test\\.tsx?$/); +const allTestFiles = getFilesInDirectory("src", /\.test\.tsx?$/); await build({ type: "test", diff --git a/packages/challenger-webui/test.mjs b/packages/challenger-webui/test.mjs @@ -18,7 +18,7 @@ import { build } from "@gnu-taler/web-util/build"; import { getFilesInDirectory } from "@gnu-taler/web-util/build"; -const allTestFiles = getFilesInDirectory("src", /\\.test\\.tsx?$/); +const allTestFiles = getFilesInDirectory("src", /\.test\.tsx?$/); await build({ type: "test", diff --git a/packages/idb-bridge/package.json b/packages/idb-bridge/package.json @@ -10,7 +10,7 @@ "license": "AGPL-3.0-or-later", "private": false, "scripts": { - "test": "tsc && node --test lib/*.test.js lib/**/*.test.js", + "test": "tsc && node --test 'lib/*.test.js' 'lib/**/*.test.js'", "typedoc": "pnpm dlx typedoc --out dist/typedoc ./src/", "compile": "tsc", "clean": "rm -rf dist lib tsconfig.tsbuildinfo", diff --git a/packages/libeufin-bank-webui/test.mjs b/packages/libeufin-bank-webui/test.mjs @@ -18,7 +18,7 @@ import { build } from "@gnu-taler/web-util/build"; import { getFilesInDirectory } from "@gnu-taler/web-util/build"; -const allTestFiles = getFilesInDirectory("src", /\\.test\\.tsx?$/); +const allTestFiles = getFilesInDirectory("src", /\.test\.tsx?$/); await build({ type: "test", diff --git a/packages/pogen/package.json b/packages/pogen/package.json @@ -8,7 +8,7 @@ "license": "GPL-2.0+", "scripts": { "clean": "rm -rf lib", - "test": "tsc && node --test lib/*.test.js lib/**/*.test.js", + "test": "tsc && node --test 'lib/*.test.js' 'lib/**/*.test.js'", "compile": "tsc" }, "type": "module", diff --git a/packages/taler-auditor-webui/test.mjs b/packages/taler-auditor-webui/test.mjs @@ -18,7 +18,7 @@ import { build } from "@gnu-taler/web-util/build"; import { getFilesInDirectory } from "@gnu-taler/web-util/build"; -const allTestFiles = getFilesInDirectory("src", /\\.test\\.tsx?$/); +const allTestFiles = getFilesInDirectory("src", /\.test\.tsx?$/); await build({ type: "test", diff --git a/packages/taler-exchange-aml-webui/test.mjs b/packages/taler-exchange-aml-webui/test.mjs @@ -18,7 +18,7 @@ import { build } from "@gnu-taler/web-util/build"; import { getFilesInDirectory } from "@gnu-taler/web-util/build"; -const allTestFiles = getFilesInDirectory("./src", /\\.test\\.tsx?$/); +const allTestFiles = getFilesInDirectory("./src", /\.test\.tsx?$/); await build({ type: "test", diff --git a/packages/taler-exchange-kyc-webui/test.mjs b/packages/taler-exchange-kyc-webui/test.mjs @@ -18,7 +18,7 @@ import { build } from "@gnu-taler/web-util/build"; import { getFilesInDirectory } from "@gnu-taler/web-util/build"; -const allTestFiles = getFilesInDirectory("src", /\\.test\\.tsx?$/); +const allTestFiles = getFilesInDirectory("src", /\.test\.tsx?$/); await build({ type: "test", diff --git a/packages/taler-merchant-webui/test.mjs b/packages/taler-merchant-webui/test.mjs @@ -18,7 +18,7 @@ import { build } from "@gnu-taler/web-util/build"; import { getFilesInDirectory } from "@gnu-taler/web-util/build"; -const allTestFiles = getFilesInDirectory("src", /\\.test\\.tsx?$/); +const allTestFiles = getFilesInDirectory("src", /\.test\.tsx?$/); await build({ type: "test", diff --git a/packages/taler-util/package.json b/packages/taler-util/package.json @@ -62,8 +62,8 @@ }, "scripts": { "compile": "tsc", - "test": "tsc && node --test lib/*.test.js lib/**/*.test.js", - "coverage": "tsc && c8 --src src --all node --test lib/*.test.js lib/**/*.test.js", + "test": "tsc && node --test 'lib/*.test.js' 'lib/**/*.test.js'", + "coverage": "tsc && c8 --src src --all node --test 'lib/*.test.js' 'lib/**/*.test.js'", "clean": "rm -rf dist lib tsconfig.tsbuildinfo", "typedoc": "pnpm dlx typedoc --out dist/typedoc ./src/", "pretty": "prettier --write src" diff --git a/packages/taler-wallet-core/package.json b/packages/taler-wallet-core/package.json @@ -14,10 +14,10 @@ "scripts": { "compile": "tsc", "pretty": "prettier --write src", - "test": "tsc && node --test lib/*.test.js lib/**/*.test.js", + "test": "tsc && node --test 'lib/*.test.js' 'lib/**/*.test.js'", "typedoc": "pnpm dlx typedoc --out dist/typedoc ./src/", - "coverage": "tsc && c8 --src src --all node --test lib/*.test.js lib/**/*.test.js", - "coverage:html": "tsc && c8 -r html --src src --all node --test lib/*.test.js lib/**/*.test.js", + "coverage": "tsc && c8 --src src --all node --test 'lib/*.test.js' 'lib/**/*.test.js'", + "coverage:html": "tsc && c8 -r html --src src --all node --test 'lib/*.test.js' 'lib/**/*.test.js'", "clean": "rm -rf dist lib tsconfig.tsbuildinfo" }, "files": [ diff --git a/packages/taler-wallet-webextension/src/cta/Payment/Payment.test.ts b/packages/taler-wallet-webextension/src/cta/Payment/Payment.test.ts @@ -1,430 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ - -/** - * - * @author Sebastian Javier Marchano (sebasjm) - */ - -import { describe, it, after } from "node:test"; - -import { - Amounts, - ConfirmPayResult, - ConfirmPayResultType, - Duration, - MerchantContractTermsV0, - NotificationType, - PreparePayResultInsufficientBalance, - PreparePayResultPaymentPossible, - PreparePayResultType, -} from "@gnu-taler/taler-util"; -import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import * as tests from "@gnu-taler/web-util/testing"; -import { expect } from "chai"; -import { nullFunction } from "../../mui/handlers.js"; -import { createWalletApiMock } from "../../test-utils.js"; -import { useComponentStateFromUri as useComponentState } from "./state.js"; - -describe("Payment CTA states", () => { - it("should tell the user that the URI is missing", async () => { - const { handler, TestingContext } = createWalletApiMock(); - const props = { - talerPayUri: "", - cancel: nullFunction, - goToWalletManualWithdraw: nullFunction, - onSuccess: nullFunction, - }; - - const hookBehavior = await tests.hookBehaveLikeThis( - useComponentState, - props, - [ - ({ status, error }) => { - expect(status).equals("loading"); - expect(error).undefined; - }, - ({ status, error }) => { - expect(status).equals("error"); - if (error === undefined) expect.fail(); - }, - ], - TestingContext, - ); - - expect(hookBehavior).deep.equal({ result: "ok" }); - expect(handler.getCallingQueueState()).eq("empty"); - }); - - it("should response with no balance", async () => { - const { handler, TestingContext } = createWalletApiMock(); - const props = { - talerPayUri: "taller://pay", - cancel: nullFunction, - goToWalletManualWithdraw: nullFunction, - onSuccess: nullFunction, - }; - - handler.addWalletCallResponse( - WalletApiOperation.PreparePayForUri, - undefined, - { - status: PreparePayResultType.InsufficientBalance, - amountRaw: "USD:10", - contractTerms: { - pay_deadline: Duration.toTalerProtocolDuration(Duration.getForever()), - } as unknown as MerchantContractTermsV0, - } as PreparePayResultInsufficientBalance, - ); - - const hookBehavior = await tests.hookBehaveLikeThis( - useComponentState, - props, - [ - ({ status, error }) => { - expect(status).equals("loading"); - expect(error).undefined; - }, - (state) => { - if (state.status !== "no-enough-balance") { - expect(state).eq({}); - return; - } - // expect(state.balance).undefined; - expect(state.amount).deep.equal(Amounts.parseOrThrow("USD:10")); - }, - ], - TestingContext, - ); - - expect(hookBehavior).deep.equal({ result: "ok" }); - expect(handler.getCallingQueueState()).eq("empty"); - }); - - it("should not be able to pay if there is no enough balance", async () => { - const { handler, TestingContext } = createWalletApiMock(); - const props = { - talerPayUri: "taller://pay", - cancel: nullFunction, - goToWalletManualWithdraw: nullFunction, - onSuccess: nullFunction, - }; - - handler.addWalletCallResponse( - WalletApiOperation.PreparePayForUri, - undefined, - { - status: PreparePayResultType.InsufficientBalance, - amountRaw: "USD:10", - contractTerms: { - pay_deadline: Duration.toTalerProtocolDuration(Duration.getForever()), - } as unknown as MerchantContractTermsV0, - } as PreparePayResultInsufficientBalance, - ); - - const hookBehavior = await tests.hookBehaveLikeThis( - useComponentState, - props, - [ - ({ status, error }) => { - expect(status).equals("loading"); - expect(error).undefined; - }, - (state) => { - if (state.status !== "no-enough-balance") expect.fail(); - // expect(state.balance).deep.equal(Amounts.parseOrThrow("USD:5")); - expect(state.amount).deep.equal(Amounts.parseOrThrow("USD:10")); - }, - ], - TestingContext, - ); - - expect(hookBehavior).deep.equal({ result: "ok" }); - expect(handler.getCallingQueueState()).eq("empty"); - }); - - it("should be able to pay (without fee)", async () => { - const { handler, TestingContext } = createWalletApiMock(); - const props = { - talerPayUri: "taller://pay", - cancel: nullFunction, - goToWalletManualWithdraw: nullFunction, - onSuccess: nullFunction, - }; - - handler.addWalletCallResponse( - WalletApiOperation.PreparePayForUri, - undefined, - { - status: PreparePayResultType.PaymentPossible, - amountRaw: "USD:10", - amountEffective: "USD:10", - contractTerms: { - pay_deadline: Duration.toTalerProtocolDuration(Duration.getForever()), - } as unknown as MerchantContractTermsV0, - } as PreparePayResultPaymentPossible, - ); - - const hookBehavior = await tests.hookBehaveLikeThis( - useComponentState, - props, - [ - ({ status, error }) => { - expect(status).equals("loading"); - expect(error).undefined; - }, - (state) => { - if (state.status !== "ready") { - expect(state).eq({}); - return; - } - // expect(state.balance).deep.equal(Amounts.parseOrThrow("USD:15")); - expect(state.amount).deep.equal(Amounts.parseOrThrow("USD:10")); - expect(state.payHandler.onClick).not.undefined; - }, - ], - TestingContext, - ); - - expect(hookBehavior).deep.equal({ result: "ok" }); - expect(handler.getCallingQueueState()).eq("empty"); - }); - - it("should be able to pay (with fee)", async () => { - const { handler, TestingContext } = createWalletApiMock(); - const props = { - talerPayUri: "taller://pay", - cancel: nullFunction, - goToWalletManualWithdraw: nullFunction, - onSuccess: nullFunction, - }; - - handler.addWalletCallResponse( - WalletApiOperation.PreparePayForUri, - undefined, - { - status: PreparePayResultType.PaymentPossible, - amountRaw: "USD:9", - amountEffective: "USD:10", - contractTerms: { - pay_deadline: Duration.toTalerProtocolDuration(Duration.getForever()), - } as unknown as MerchantContractTermsV0, - } as PreparePayResultPaymentPossible, - ); - - const hookBehavior = await tests.hookBehaveLikeThis( - useComponentState, - props, - [ - ({ status, error }) => { - expect(status).equals("loading"); - expect(error).undefined; - }, - (state) => { - if (state.status !== "ready") expect.fail(); - // expect(state.balance).deep.equal(Amounts.parseOrThrow("USD:15")); - expect(state.amount).deep.equal(Amounts.parseOrThrow("USD:9")); - expect(state.payHandler.onClick).not.undefined; - }, - ], - TestingContext, - ); - - expect(hookBehavior).deep.equal({ result: "ok" }); - expect(handler.getCallingQueueState()).eq("empty"); - }); - - it("should get confirmation done after pay successfully", async () => { - const { handler, TestingContext } = createWalletApiMock(); - const props = { - talerPayUri: "taller://pay", - cancel: nullFunction, - goToWalletManualWithdraw: nullFunction, - onSuccess: nullFunction, - }; - - handler.addWalletCallResponse( - WalletApiOperation.PreparePayForUri, - undefined, - { - status: PreparePayResultType.PaymentPossible, - amountRaw: "USD:9", - amountEffective: "USD:10", - contractTerms: { - pay_deadline: Duration.toTalerProtocolDuration(Duration.getForever()), - } as unknown as MerchantContractTermsV0, - } as PreparePayResultPaymentPossible, - ); - - handler.addWalletCallResponse(WalletApiOperation.ConfirmPay, undefined, { - type: ConfirmPayResultType.Done, - contractTerms: {}, - } as ConfirmPayResult); - - const hookBehavior = await tests.hookBehaveLikeThis( - useComponentState, - props, - [ - ({ status, error }) => { - expect(status).equals("loading"); - expect(error).undefined; - }, - (state) => { - if (state.status !== "ready") { - expect(state).eq({}); - return; - } - // expect(state.balance).deep.equal(Amounts.parseOrThrow("USD:15")); - expect(state.amount).deep.equal(Amounts.parseOrThrow("USD:9")); - if (state.payHandler.onClick === undefined) expect.fail(); - state.payHandler.onClick(); - }, - ], - TestingContext, - ); - - expect(hookBehavior).deep.equal({ result: "ok" }); - expect(handler.getCallingQueueState()).eq("empty"); - }); - - it("should not stay in ready state after pay with error", async () => { - const { handler, TestingContext } = createWalletApiMock(); - const props = { - talerPayUri: "taller://pay", - cancel: nullFunction, - goToWalletManualWithdraw: nullFunction, - onSuccess: nullFunction, - }; - handler.addWalletCallResponse( - WalletApiOperation.PreparePayForUri, - undefined, - { - status: PreparePayResultType.PaymentPossible, - amountRaw: "USD:9", - amountEffective: "USD:10", - contractTerms: { - pay_deadline: Duration.toTalerProtocolDuration(Duration.getForever()), - } as unknown as MerchantContractTermsV0, - } as PreparePayResultPaymentPossible, - ); - - handler.addWalletCallResponse(WalletApiOperation.ConfirmPay, undefined, { - type: ConfirmPayResultType.Pending, - lastError: { code: 1 }, - } as ConfirmPayResult); - - // const hookBehavior = await tests.hookBehaveLikeThis( - // () => { - // const state = useComponentState(props); - // // const { alerts } = useAlertContext(); - // return { ...state, alerts: {} }; - // }, - // {}, - // [ - // ({ status, error }) => { - // expect(status).equals("loading"); - // expect(error).undefined; - // }, - // (state) => { - // if (state.status !== "ready") expect.fail(); - // // expect(state.balance).deep.equal(Amounts.parseOrThrow("USD:15")); - // expect(state.amount).deep.equal(Amounts.parseOrThrow("USD:9")); - // // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1")); - // if (state.payHandler.onClick === undefined) expect.fail(); - // state.payHandler.onClick(); - // }, - // ], - // TestingContext, - // ); - - // expect(hookBehavior).deep.equal({ result: "ok" }); - expect(handler.getCallingQueueState()).eq("empty"); - }); - - it("should update balance if a coins is withdraw", async () => { - const { handler, TestingContext } = createWalletApiMock(); - - const props = { - talerPayUri: "taller://pay", - cancel: nullFunction, - goToWalletManualWithdraw: nullFunction, - onSuccess: nullFunction, - }; - - handler.addWalletCallResponse( - WalletApiOperation.PreparePayForUri, - undefined, - { - status: PreparePayResultType.PaymentPossible, - amountRaw: "USD:9", - amountEffective: "USD:10", - contractTerms: { - pay_deadline: Duration.toTalerProtocolDuration(Duration.getForever()), - } as unknown as MerchantContractTermsV0, - } as PreparePayResultPaymentPossible, - ); - - handler.addWalletCallResponse( - WalletApiOperation.PreparePayForUri, - undefined, - { - status: PreparePayResultType.PaymentPossible, - amountRaw: "USD:9", - amountEffective: "USD:10", - contractTerms: { - pay_deadline: Duration.toTalerProtocolDuration(Duration.getForever()), - } as unknown as MerchantContractTermsV0, - } as PreparePayResultPaymentPossible, - ); - - const hookBehavior = await tests.hookBehaveLikeThis( - useComponentState, - props, - [ - ({ status, error }) => { - expect(status).equals("loading"); - expect(error).undefined; - }, - (state) => { - if (state.status !== "ready") expect.fail(); - // expect(state.balance).deep.equal(Amounts.parseOrThrow("USD:10")); - expect(state.amount).deep.equal(Amounts.parseOrThrow("USD:9")); - // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1")); - expect(state.payHandler.onClick).not.undefined; - - handler.notifyEventFromWallet({ - type: NotificationType.TransactionStateTransition, - newTxState: {} as any, - oldTxState: {} as any, - transactionId: "123", - newStId: 1, - }); - }, - (state) => { - if (state.status !== "ready") expect.fail(); - // expect(state.balance).deep.equal(Amounts.parseOrThrow("USD:15")); - expect(state.amount).deep.equal(Amounts.parseOrThrow("USD:9")); - // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1")); - expect(state.payHandler.onClick).not.undefined; - }, - ], - TestingContext, - ); - - expect(hookBehavior).deep.equal({ result: "ok" }); - expect(handler.getCallingQueueState()).eq("empty"); - }); -}); diff --git a/packages/taler-wallet-webextension/src/stories.test.ts b/packages/taler-wallet-webextension/src/stories.test.ts @@ -1,67 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ - -/** - * - * @author Sebastian Javier Marchano (sebasjm) - */ - -import { describe, it } from "node:test"; -import { setupI18n } from "@gnu-taler/taler-util"; -import { parseGroupImport } from "@gnu-taler/web-util/browser"; -import * as tests from "@gnu-taler/web-util/testing"; -import chromeAPI from "./platform/chrome.js"; -import { setupPlatform } from "./platform/foreground.js"; - -import * as components from "./components/index.stories.js"; -import * as cta from "./cta/index.stories.js"; -import * as mui from "./mui/index.stories.js"; -import * as popup from "./popup/index.stories.js"; -import * as wallet from "./wallet/index.stories.js"; -// import { renderNodeOrBrowser } from "./test-utils.js"; -import { h, VNode, ComponentChildren } from "preact"; -import { AlertProvider } from "./context/alert.js"; - -setupI18n("en", { en: {} }); -setupPlatform(chromeAPI); - -describe("All the examples:", () => { - const cms = parseGroupImport({ popup, wallet, cta, mui, components }); - cms.forEach((group) => { - describe(`Example for group "${group.title}:"`, () => { - group.list.forEach((component) => { - describe(`Component ${component.name}:`, () => { - component.examples.forEach((example) => { - it(`should render example: ${example.name}`, () => { - tests.renderUI(example.render, DefaultTestingContext); - }); - }); - }); - }); - }); - }); -}); -function DefaultTestingContext({ - children, -}: { - children: ComponentChildren; -}): VNode { - //FIXME: - //some components push the alter in the UI function - //that's not correct, should be moved into the state function - // until then, we ran the tests with the alert provider - return h(AlertProvider, { children }); -} diff --git a/packages/taler-wallet-webextension/test.mjs b/packages/taler-wallet-webextension/test.mjs @@ -17,7 +17,7 @@ import { build, getFilesInDirectory } from "@gnu-taler/web-util/build"; -const allTestFiles = getFilesInDirectory("src", /\\.test\\.tsx?$/); +const allTestFiles = getFilesInDirectory("src", /\.test\.tsx?$/); await build({ type: "test", diff --git a/packages/web-util/src/index.build.ts b/packages/web-util/src/index.build.ts @@ -268,6 +268,10 @@ export function computeConfig(params: BuildParams): { __VERSION__: `"${version}"`, __GIT_HASH__: `"${GIT_HASH}"`, }, + // Test files import node: built-in modules (e.g. node:test, node:assert) + // which can't be resolved with platform:"browser". Mark them as external + // so they are resolved by Node.js at runtime. + ...(params.type === "test" ? { external: ["node:*"] } : {}), plugins, };