commit 6fe8ee28957cb1232d5c1b2c8e898013f38ae790
parent e97557f198bc8a3fd7585537149ac7a013c26b5c
Author: Florian Dold <dold@taler.net>
Date: Tue, 22 Sep 2026 22:28:30 +0200
wallet API: accept state specifications in bailStates
Diffstat:
4 files changed, 35 insertions(+), 16 deletions(-)
diff --git a/packages/taler-util/src/types-taler-wallet.test.ts b/packages/taler-util/src/types-taler-wallet.test.ts
@@ -157,10 +157,10 @@ test("finality of transaction states", (t) => {
}
});
-test("wait request codec accepts every form of txState", (t) => {
+test("wait request codec accepts every form of txState and bailStates", (t) => {
const codec = codecForTestingWaitTransactionRequest();
const transactionId = "txn:withdrawal:foo";
- for (const txState of [
+ for (const spec of [
"nonpending",
"final",
42,
@@ -168,14 +168,23 @@ test("wait request codec accepts every form of txState", (t) => {
{ major: "*", minor: "*", working: true },
[{ major: "failed", minor: "*" }, { major: "done" }],
]) {
- const req = codec.decode({ transactionId, txState });
+ const req = codec.decode({
+ transactionId,
+ txState: spec,
+ bailStates: spec,
+ });
assert.strictEqual(req.progressToken, undefined);
// The codec adds the optional properties as undefined, which
// JSON drops again.
assert.deepStrictEqual(
JSON.parse(JSON.stringify(req.txState)),
- txState,
- JSON.stringify(txState),
+ spec,
+ JSON.stringify(spec),
+ );
+ assert.deepStrictEqual(
+ JSON.parse(JSON.stringify(req.bailStates)),
+ spec,
+ JSON.stringify(spec),
);
}
const full = codec.decode({
@@ -199,16 +208,25 @@ test("wait request codec rejects bad input", (t) => {
const transactionId = "txn:withdrawal:foo";
const bad = [
{ transactionId, txState: "final", progressToken: 42 },
- { transactionId, txState: { major: "dnoe" } },
- { transactionId, txState: { major: "done", minor: "kyc-required" } },
- { transactionId, txState: "whenever" },
- { transactionId, txState: { major: "done", working: "yes" } },
{ transactionId: "withdrawal:foo", txState: "final" },
{ transactionId },
];
for (const req of bad) {
assert.throws(() => codec.decode(req), JSON.stringify(req));
}
+ for (const field of ["txState", "bailStates"]) {
+ for (const spec of [
+ { major: "dnoe" },
+ { major: "done", minor: "kyc-required" },
+ "whenever",
+ { major: "done", working: "yes" },
+ [{ major: "dnoe" }],
+ true,
+ ]) {
+ const req = { transactionId, txState: "final", [field]: spec };
+ assert.throws(() => codec.decode(req), JSON.stringify(req));
+ }
+ }
});
test("legacy wait request codec is an alias of the stable codec", () => {
diff --git a/packages/taler-util/src/types-taler-wallet.ts b/packages/taler-util/src/types-taler-wallet.ts
@@ -4164,7 +4164,7 @@ export interface WaitTransactionStateRequest {
* Without this, a transaction that ends up in a state it will
* never leave keeps the caller waiting until the timeout.
*/
- bailStates?: TransactionStatePattern[];
+ bailStates?: TestingWaitTxStateSpec;
/**
* End the wait as soon as an error is recorded for the transaction.
@@ -4262,10 +4262,7 @@ export const codecForWaitTransactionStateRequest =
.property("timeout", codecOptional(codecForDurationUnitSpec()))
.property("requireError", codecOptional(codecForBoolean()))
.property("txState", codecForTestingWaitTxStateSpec())
- .property(
- "bailStates",
- codecOptional(codecForList(codecForTransactionStatePattern())),
- )
+ .property("bailStates", codecOptional(codecForTestingWaitTxStateSpec()))
.property("bailOnError", codecOptional(codecForBoolean()))
.build("WaitTransactionStateRequest");
diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts
@@ -1257,7 +1257,7 @@ interface WaitTxRequest {
* Timeout in milliseconds, or undefined to wait forever.
*/
timeoutMs?: number;
- bailStates?: TransactionStatePattern[];
+ bailStates?: TestingWaitTxStateSpec;
bailOnError?: boolean;
requireError?: boolean;
logId?: string;
diff --git a/packages/taler-wallet-core/src/testing.test.ts b/packages/taler-wallet-core/src/testing.test.ts
@@ -341,7 +341,11 @@ test("target/error and bail matching retain their precedence", async (t) => {
requireError: true,
bailStates: [{ major: TransactionMajorState.Done }],
},
- ]) {
+ { txState: 999, bailStates: { major: TransactionMajorState.Done } },
+ { txState: 999, bailStates: 1 },
+ { txState: 999, bailStates: "final" },
+ { txState: 999, bailStates: "nonpending" },
+ ] satisfies Partial<TestingWaitTransactionRequest>[]) {
assert.equal(
(await f.start({ progressToken: "bail", ...req }).result).matched,
"bail",