vona-module-test-pay 5.0.1 → 5.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -4
- package/test/outbox.test.ts +14 -4
- package/test/payMock.test.ts +13 -3
- package/test/paymentSession.test.ts +26 -8
- package/test/webhook.test.ts +12 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vona-module-test-pay",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Vona Module"
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"postpack": "clean-package restore"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"vona-module-a-pay": "5.0.
|
|
34
|
-
"vona-module-pay-mock": "5.0.
|
|
33
|
+
"vona-module-a-pay": "5.0.3",
|
|
34
|
+
"vona-module-pay-mock": "5.0.3"
|
|
35
35
|
},
|
|
36
36
|
"title": "test-pay",
|
|
37
37
|
"vonaModule": {
|
|
@@ -51,5 +51,5 @@
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "e86b8ee51b837417b7b28b2c67862877d4092371"
|
|
55
55
|
}
|
package/test/outbox.test.ts
CHANGED
|
@@ -2,8 +2,8 @@ import type { IPaymentOutcomeEvent } from 'vona-module-a-pay';
|
|
|
2
2
|
|
|
3
3
|
import assert from 'node:assert';
|
|
4
4
|
import { randomUUID } from 'node:crypto';
|
|
5
|
-
import { describe, it } from 'node:test';
|
|
6
|
-
import { app } from 'vona-mock';
|
|
5
|
+
import { after, before, describe, it } from 'node:test';
|
|
6
|
+
import { acquireTestLock, app } from 'vona-mock';
|
|
7
7
|
|
|
8
8
|
interface IFixture {
|
|
9
9
|
userId?: number;
|
|
@@ -79,6 +79,16 @@ async function cleanup(fixture: IFixture) {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
describe('outbox.test.ts', { concurrency: false }, () => {
|
|
82
|
+
let releaseTestLock: (() => void) | undefined;
|
|
83
|
+
|
|
84
|
+
before(async () => {
|
|
85
|
+
releaseTestLock = await acquireTestLock('a-pay');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
after(() => {
|
|
89
|
+
releaseTestLock?.();
|
|
90
|
+
});
|
|
91
|
+
|
|
82
92
|
it('claims, backs off, and exhausts durable delivery attempts', async () => {
|
|
83
93
|
await app.bean.executor.mockCtx(async () => {
|
|
84
94
|
const fixture = await createFixture(randomUUID().slice(0, 12));
|
|
@@ -100,7 +110,7 @@ describe('outbox.test.ts', { concurrency: false }, () => {
|
|
|
100
110
|
assert.ok((persisted?.nextAttemptAt?.getTime() ?? 0) >= releaseStart + 900);
|
|
101
111
|
assert.equal(await scope.service.outbox.claim(event.id), undefined);
|
|
102
112
|
await scope.model.outboxEvent.updateById(event.id, {
|
|
103
|
-
nextAttemptAt: new Date(Date.now() -
|
|
113
|
+
nextAttemptAt: new Date(Date.now() - 1_000),
|
|
104
114
|
});
|
|
105
115
|
const second = await scope.service.outbox.claim(event.id);
|
|
106
116
|
assert.equal(second?.attemptCount, 2);
|
|
@@ -150,7 +160,7 @@ describe('outbox.test.ts', { concurrency: false }, () => {
|
|
|
150
160
|
const scope = app.scope('a-pay');
|
|
151
161
|
const first = await scope.service.outbox.claim(event.id);
|
|
152
162
|
await scope.model.outboxEvent.updateById(event.id, {
|
|
153
|
-
claimExpiresAt: new Date(Date.now() -
|
|
163
|
+
claimExpiresAt: new Date(Date.now() - 1_000),
|
|
154
164
|
});
|
|
155
165
|
const second = await scope.service.outbox.claim(event.id);
|
|
156
166
|
assert.ok(second?.claimToken);
|
package/test/payMock.test.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import assert from 'node:assert';
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
|
-
import { describe, it } from 'node:test';
|
|
4
|
-
import { app } from 'vona-mock';
|
|
3
|
+
import { after, before, describe, it } from 'node:test';
|
|
4
|
+
import { acquireTestLock, app } from 'vona-mock';
|
|
5
5
|
|
|
6
6
|
interface IFixture {
|
|
7
7
|
userId?: number;
|
|
@@ -38,7 +38,17 @@ async function cleanup(fixture: IFixture) {
|
|
|
38
38
|
await app.bean.passport.signout();
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
describe('payMock.test.ts', { concurrency: false }, () => {
|
|
41
|
+
describe('payMock.test.ts', { concurrency: false, sequential: true }, () => {
|
|
42
|
+
let releaseTestLock: (() => void) | undefined;
|
|
43
|
+
|
|
44
|
+
before(async () => {
|
|
45
|
+
releaseTestLock = await acquireTestLock('a-pay');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
after(() => {
|
|
49
|
+
releaseTestLock?.();
|
|
50
|
+
});
|
|
51
|
+
|
|
42
52
|
it('captures Vona env secrets in the mock Provider options', () => {
|
|
43
53
|
const options = app.bean.payProvider.getOptions('pay-mock:mock', 'default');
|
|
44
54
|
assert.equal(options.secretCredential, app.meta.env.PAY_MOCK_DEFAULT_CREDENTIAL);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import assert from 'node:assert';
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
|
-
import { describe, it } from 'node:test';
|
|
4
|
-
import { app } from 'vona-mock';
|
|
3
|
+
import { after, before, describe, it } from 'node:test';
|
|
4
|
+
import { acquireTestLock, app } from 'vona-mock';
|
|
5
5
|
|
|
6
6
|
interface IFixture {
|
|
7
7
|
userId?: number;
|
|
@@ -27,6 +27,10 @@ async function createFixture(expiresAt: Date): Promise<IFixture> {
|
|
|
27
27
|
async function cleanup(fixture: IFixture) {
|
|
28
28
|
const scope = app.scope('a-pay');
|
|
29
29
|
if (fixture.paymentSessionId !== undefined) {
|
|
30
|
+
await scope.model.outboxEvent.delete({ paymentSessionId: fixture.paymentSessionId });
|
|
31
|
+
await scope.model.webhookInbox.delete({ paymentSessionId: fixture.paymentSessionId });
|
|
32
|
+
await scope.model.providerOperation.delete({ paymentSessionId: fixture.paymentSessionId });
|
|
33
|
+
await scope.model.refundOperation.delete({ paymentSessionId: fixture.paymentSessionId });
|
|
30
34
|
await scope.model.paymentAudit.delete({ paymentSessionId: fixture.paymentSessionId });
|
|
31
35
|
await scope.model.paymentSession.delete({ id: fixture.paymentSessionId });
|
|
32
36
|
}
|
|
@@ -37,6 +41,16 @@ async function cleanup(fixture: IFixture) {
|
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
describe('paymentSession.test.ts', { concurrency: false }, () => {
|
|
44
|
+
let releaseTestLock: (() => void) | undefined;
|
|
45
|
+
|
|
46
|
+
before(async () => {
|
|
47
|
+
releaseTestLock = await acquireTestLock('a-pay');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
after(() => {
|
|
51
|
+
releaseTestLock?.();
|
|
52
|
+
});
|
|
53
|
+
|
|
40
54
|
it('derives provider facts and expiry from the payment scene', async () => {
|
|
41
55
|
await app.bean.executor.mockCtx(async () => {
|
|
42
56
|
const scope = app.scope('a-pay');
|
|
@@ -102,9 +116,8 @@ describe('paymentSession.test.ts', { concurrency: false }, () => {
|
|
|
102
116
|
const scope = app.scope('a-pay');
|
|
103
117
|
const session = await scope.service.paymentSession.start(fixture.paymentSessionId!);
|
|
104
118
|
assert.equal(session.state, 'requires_action');
|
|
105
|
-
await
|
|
106
|
-
|
|
107
|
-
});
|
|
119
|
+
const replayed = await scope.service.paymentSession.start(fixture.paymentSessionId!);
|
|
120
|
+
assert.equal(replayed.state, 'requires_action');
|
|
108
121
|
} finally {
|
|
109
122
|
await cleanup(fixture);
|
|
110
123
|
}
|
|
@@ -113,7 +126,7 @@ describe('paymentSession.test.ts', { concurrency: false }, () => {
|
|
|
113
126
|
|
|
114
127
|
it('does not start an expired payment session', async () => {
|
|
115
128
|
await app.bean.executor.mockCtx(async () => {
|
|
116
|
-
const fixture = await createFixture(new Date(Date.now() -
|
|
129
|
+
const fixture = await createFixture(new Date(Date.now() - 1_000));
|
|
117
130
|
try {
|
|
118
131
|
const scope = app.scope('a-pay');
|
|
119
132
|
await assert.rejects(scope.service.paymentSession.start(fixture.paymentSessionId!), {
|
|
@@ -142,8 +155,13 @@ describe('paymentSession.test.ts', { concurrency: false }, () => {
|
|
|
142
155
|
return await app.scope('a-pay').service.paymentSession.start(fixture.paymentSessionId!);
|
|
143
156
|
}),
|
|
144
157
|
]);
|
|
145
|
-
assert.equal(results.filter(result => result.status === 'fulfilled').length,
|
|
146
|
-
|
|
158
|
+
assert.equal(results.filter(result => result.status === 'fulfilled').length, 2);
|
|
159
|
+
const operations = await app.bean.executor.mockCtx(async () => {
|
|
160
|
+
return await app.scope('a-pay').model.providerOperation.select({
|
|
161
|
+
where: { paymentSessionId: fixture.paymentSessionId, kind: 'start' },
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
assert.equal(operations.length, 1);
|
|
147
165
|
} finally {
|
|
148
166
|
await app.bean.executor.mockCtx(async () => {
|
|
149
167
|
await cleanup(fixture);
|
package/test/webhook.test.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import assert from 'node:assert';
|
|
2
2
|
import { createHmac, randomUUID } from 'node:crypto';
|
|
3
|
-
import { describe, it } from 'node:test';
|
|
4
|
-
import { app } from 'vona-mock';
|
|
3
|
+
import { after, before, describe, it } from 'node:test';
|
|
4
|
+
import { acquireTestLock, app } from 'vona-mock';
|
|
5
5
|
|
|
6
6
|
interface IFixture {
|
|
7
7
|
userId?: number;
|
|
@@ -100,6 +100,16 @@ async function countFacts(paymentSessionId: number) {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
describe('webhook.test.ts', { concurrency: false, sequential: true }, () => {
|
|
103
|
+
let releaseTestLock: (() => void) | undefined;
|
|
104
|
+
|
|
105
|
+
before(async () => {
|
|
106
|
+
releaseTestLock = await acquireTestLock('a-pay');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
after(() => {
|
|
110
|
+
releaseTestLock?.();
|
|
111
|
+
});
|
|
112
|
+
|
|
103
113
|
it('accepts a raw-body signed HTTP webhook and rejects an invalid signature without mutation', async () => {
|
|
104
114
|
const fixture: IFixture = {};
|
|
105
115
|
try {
|