Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(backend): support Open Payments connection as receiver #603

Merged
merged 11 commits into from
Sep 23, 2022
Merged
2 changes: 1 addition & 1 deletion packages/backend/src/config/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export const Config = {

openPaymentsSpec: envString(
'OPEN_PAYMENTS_SPEC',
'https://raw.githubusercontent.com/interledger/open-payments/bc90cb63e99e56b85abe25f2018393c7b21f6648/open-api-spec.yaml'
'https://raw.githubusercontent.com/interledger/open-payments/499d551e36fb42614feeadd4aa3af90bb2a4fcff/open-api-spec.yaml'
),
authServerSpec: envString(
'AUTH_SERVER_SPEC',
Expand Down
110 changes: 68 additions & 42 deletions packages/backend/src/open_payments/client/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ describe('Open Payments Client Service', (): void => {
let clientService: OpenPaymentsClientService
let knex: Knex

const CONNECTION_PATH = 'connections'
const INCOMING_PAYMENT_PATH = 'incoming-payments'

beforeAll(async (): Promise<void> => {
deps = await initIocContainer(Config)
appContainer = await createTestApp(deps)
Expand All @@ -35,74 +38,97 @@ describe('Open Payments Client Service', (): void => {
afterAll(async (): Promise<void> => {
await appContainer.shutdown()
})
describe('incomingPayment.get', (): void => {
test.each`
incomingAmount | description | externalRef
${undefined} | ${undefined} | ${undefined}
${BigInt(123)} | ${'Test'} | ${'#123'}
`(
'resolves incoming payment from Open Payments server',
async ({ incomingAmount, description, externalRef }): Promise<void> => {
describe.each`
urlPath | description
${CONNECTION_PATH} | ${'connection'}
${INCOMING_PAYMENT_PATH} | ${'incoming payment'}
`('receiver.get - $description', ({ urlPath }): void => {
if (urlPath === CONNECTION_PATH) {
test('resolves connection from Open Payments server', async (): Promise<void> => {
const paymentPointer = await createPaymentPointer(deps, {
mockServerPort: appContainer.openPaymentsPort
})
const incomingPayment = await createIncomingPayment(deps, {
paymentPointerId: paymentPointer.id,
description,
incomingAmount: incomingAmount && {
value: incomingAmount,
assetCode: paymentPointer.asset.code,
assetScale: paymentPointer.asset.scale
},
externalRef
paymentPointerId: paymentPointer.id
})
const resolvedPayment = await clientService.incomingPayment.get(
incomingPayment.url
const receiver = await clientService.receiver.get(
`${Config.openPaymentsUrl}/${urlPath}/${incomingPayment.connectionId}`
)
paymentPointer.scope.isDone()
expect(resolvedPayment).toEqual({
...incomingPayment.toJSON(),
id: incomingPayment.url,
paymentPointer: incomingPayment.paymentPointer.url,
ilpStreamConnection: {
id: `${Config.openPaymentsUrl}/connections/${incomingPayment.connectionId}`,
ilpAddress: expect.any(String),
sharedSecret: expect.any(String)
}
})
}
)
expect(receiver.assetCode).toEqual(paymentPointer.asset.code)
expect(receiver.assetScale).toEqual(paymentPointer.asset.scale)
expect(receiver.incomingAmount).toBeUndefined()
expect(receiver.receivedAmount).toBeUndefined()
expect(receiver.ilpAddress).toEqual(expect.any(String))
expect(receiver.sharedSecret).toEqual(expect.any(Buffer))
})
} else {
test.each`
incomingAmount | description | externalRef
${undefined} | ${undefined} | ${undefined}
${BigInt(123)} | ${'Test'} | ${'#123'}
`(
'resolves incoming payment from Open Payments server',
async ({ incomingAmount, description, externalRef }): Promise<void> => {
const paymentPointer = await createPaymentPointer(deps, {
mockServerPort: appContainer.openPaymentsPort
})
const incomingPayment = await createIncomingPayment(deps, {
paymentPointerId: paymentPointer.id,
description,
incomingAmount: incomingAmount && {
value: incomingAmount,
assetCode: paymentPointer.asset.code,
assetScale: paymentPointer.asset.scale
},
externalRef
})
const receiver = await clientService.receiver.get(incomingPayment.url)
paymentPointer.scope.isDone()
expect(receiver.assetCode).toEqual(paymentPointer.asset.code)
expect(receiver.assetScale).toEqual(paymentPointer.asset.scale)
expect(receiver.incomingAmount).toEqual(
incomingPayment.incomingAmount
)
expect(receiver.receivedAmount).toEqual(
incomingPayment.receivedAmount
)
expect(receiver.ilpAddress).toEqual(expect.any(String))
expect(receiver.sharedSecret).toEqual(expect.any(Buffer))
}
)
}
test.each`
statusCode
${404}
${500}
`(
'returns undefined for unsuccessful request ($statusCode)',
async ({ statusCode }): Promise<void> => {
const incomingPaymentUrl = new URL(
`${faker.internet.url()}/incoming-payments/${uuid()}`
const receiverUrl = new URL(
`${faker.internet.url()}/${urlPath}/${uuid()}`
)
const scope = nock(incomingPaymentUrl.host)
.get(incomingPaymentUrl.pathname)
const scope = nock(receiverUrl.host)
.get(receiverUrl.pathname)
.reply(statusCode)
scope.isDone()
await expect(
clientService.incomingPayment.get(incomingPaymentUrl.href)
clientService.receiver.get(receiverUrl.href)
).resolves.toBeUndefined()
}
)
test('returns undefined for invalid incoming payment response', async (): Promise<void> => {
const incomingPaymentUrl = new URL(
`${faker.internet.url()}/incoming-payments/${uuid()}`
test(`returns undefined for invalid response`, async (): Promise<void> => {
const receiverUrl = new URL(
`${faker.internet.url()}/${urlPath}/${uuid()}`
)
const scope = nock(incomingPaymentUrl.host)
.get(incomingPaymentUrl.pathname)
const scope = nock(receiverUrl.host)
.get(receiverUrl.pathname)
.reply(200, () => ({
validPayment: 0
validReceiver: 0
}))
scope.isDone()
await expect(
clientService.incomingPayment.get(incomingPaymentUrl.href)
clientService.receiver.get(receiverUrl.href)
).resolves.toBeUndefined()
})
})
Expand Down
Loading