Skip to content

Commit e9c0cc6

Browse files
authored
Merge branch 'main' into cores-iap
2 parents 79e7a4c + 56cacd7 commit e9c0cc6

File tree

10 files changed

+428
-48
lines changed

10 files changed

+428
-48
lines changed

__tests__/__snapshots__/feeds.ts.snap

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2743,28 +2743,6 @@ Object {
27432743
}
27442744
`;
27452745

2746-
exports[`query sourceFeed should display return the right posts after the first page being a mix of pinned and unpinned posts 1`] = `
2747-
Array [
2748-
Object {
2749-
"node": Object {
2750-
"id": "p2",
2751-
"pinnedAt": null,
2752-
"readTime": null,
2753-
"source": Object {
2754-
"id": "b",
2755-
"image": "http://image.com/b",
2756-
"name": "B",
2757-
"public": true,
2758-
},
2759-
"tags": Array [],
2760-
"title": "P2",
2761-
"type": "article",
2762-
"url": "http://p2.com",
2763-
},
2764-
},
2765-
]
2766-
`;
2767-
27682746
exports[`query sourceFeed should display return the right posts after the first page being pinned posts 1`] = `
27692747
Array [
27702748
Object {

__tests__/common/njord.ts

Lines changed: 316 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@ import { usersFixture } from '../fixture';
1010
import { Product, ProductType } from '../../src/entity/Product';
1111
import type { AuthContext } from '../../src/Context';
1212
import { createClient } from '@connectrpc/connect';
13-
import { Credits, EntityType, TransferStatus } from '@dailydotdev/schema';
13+
import {
14+
Credits,
15+
Currency,
16+
EntityType,
17+
GetBalanceRequest,
18+
TransferStatus,
19+
} from '@dailydotdev/schema';
1420
import * as njordCommon from '../../src/common/njord';
1521
import { User } from '../../src/entity/user/User';
1622
import { ForbiddenError } from 'apollo-server-errors';
@@ -23,6 +29,8 @@ import * as redisFile from '../../src/redis';
2329
import { ioRedisPool } from '../../src/redis';
2430
import { parseBigInt } from '../../src/common';
2531
import { TransferError } from '../../src/errors';
32+
import { verifyJwt } from '../../src/auth';
33+
import { serviceClientId } from '../../src/types';
2634

2735
let con: DataSource;
2836

@@ -212,6 +220,47 @@ describe('transferCores', () => {
212220
}),
213221
).rejects.toBeInstanceOf(TransferError);
214222
});
223+
224+
it('should sign request', async () => {
225+
const mockTransport = createMockNjordTransport();
226+
const mockedClient = createClient(Credits, mockTransport);
227+
const clientSpy = jest.spyOn(mockedClient, 'transfer');
228+
jest
229+
.spyOn(njordCommon, 'getNjordClient')
230+
.mockImplementation(() => mockedClient);
231+
232+
const transaction = await njordCommon.createTransaction({
233+
ctx: {
234+
userId: 't-tc-1',
235+
} as unknown as AuthContext,
236+
entityManager: con.manager,
237+
productId: 'dd65570f-86c0-40a0-b8a0-3fdbd0d3945d',
238+
receiverId: 't-tc-2',
239+
note: 'Test test!',
240+
});
241+
242+
await njordCommon.transferCores({
243+
ctx: {
244+
userId: 't-tc-1',
245+
} as unknown as AuthContext,
246+
transaction,
247+
entityManager: con.manager,
248+
});
249+
250+
expect(clientSpy).toHaveBeenCalledTimes(1);
251+
expect(clientSpy).toHaveBeenCalledWith(
252+
expect.objectContaining({
253+
idempotencyKey: transaction.id,
254+
transfers: expect.toBeArrayOfSize(1),
255+
}),
256+
expect.objectContaining({
257+
headers: expect.any(Headers),
258+
}),
259+
);
260+
expect(
261+
(clientSpy.mock.calls[0][1]!.headers as Headers).get('authorization'),
262+
).toStartWith('Bearer ');
263+
});
215264
});
216265

217266
describe('getBalance', () => {
@@ -392,6 +441,36 @@ describe('getBalance', () => {
392441

393442
expect(result).toEqual({ amount: 0 });
394443
});
444+
445+
it('should sign request', async () => {
446+
const mockTransport = createMockNjordTransport();
447+
const mockedClient = createClient(Credits, mockTransport);
448+
const clientSpy = jest.spyOn(mockedClient, 'getBalance');
449+
jest
450+
.spyOn(njordCommon, 'getNjordClient')
451+
.mockImplementation(() => mockedClient);
452+
453+
const result = await njordCommon.getBalance({
454+
userId: 't-gb-1',
455+
});
456+
457+
expect(result).toEqual({ amount: 0 });
458+
expect(clientSpy).toHaveBeenCalledTimes(1);
459+
expect(clientSpy).toHaveBeenCalledWith(
460+
{
461+
account: {
462+
userId: 't-gb-1',
463+
currency: 0,
464+
},
465+
},
466+
expect.objectContaining({
467+
headers: expect.any(Headers),
468+
}),
469+
);
470+
expect(
471+
(clientSpy.mock.calls[0][1]!.headers as Headers).get('authorization'),
472+
).toStartWith('Bearer ');
473+
});
395474
});
396475

397476
describe('updatedBalanceCache', () => {
@@ -478,3 +557,239 @@ describe('expireBalanceCache', () => {
478557
expect(getFreshBalanceSpy).toHaveBeenCalledTimes(2);
479558
});
480559
});
560+
561+
describe('purchaseCores', () => {
562+
beforeEach(async () => {
563+
jest.clearAllMocks();
564+
565+
const mockTransport = createMockNjordTransport();
566+
jest
567+
.spyOn(njordCommon, 'getNjordClient')
568+
.mockImplementation(() => createClient(Credits, mockTransport));
569+
570+
await saveFixtures(
571+
con,
572+
User,
573+
usersFixture.map((item) => {
574+
return {
575+
...item,
576+
id: `t-pc-${item.id}`,
577+
username: `t-pc-${item.username}`,
578+
github: undefined,
579+
};
580+
}),
581+
);
582+
583+
await saveFixtures(con, Product, [
584+
{
585+
id: '5329e56b-b121-47cb-9c3c-58c086c1542b',
586+
name: 'Award 1',
587+
image: 'https://daily.dev/award.jpg',
588+
type: ProductType.Award,
589+
value: 42,
590+
},
591+
]);
592+
});
593+
594+
it('should purchase cores', async () => {
595+
const transaction = await con.getRepository(UserTransaction).save({
596+
processor: UserTransactionProcessor.Paddle,
597+
receiverId: 't-pc-2',
598+
status: UserTransactionStatus.Success,
599+
productId: null,
600+
senderId: null,
601+
value: 42,
602+
valueIncFees: 42,
603+
fee: 0,
604+
request: {},
605+
flags: {
606+
note: 'Test test!',
607+
},
608+
});
609+
610+
await njordCommon.purchaseCores({
611+
transaction,
612+
});
613+
614+
expect(transaction).toMatchObject({
615+
id: expect.any(String),
616+
processor: UserTransactionProcessor.Paddle,
617+
receiverId: 't-pc-2',
618+
status: UserTransactionStatus.Success,
619+
productId: null,
620+
senderId: null,
621+
value: 42,
622+
valueIncFees: 42,
623+
fee: 0,
624+
createdAt: expect.any(Date),
625+
updatedAt: expect.any(Date),
626+
flags: {
627+
note: 'Test test!',
628+
},
629+
} as UserTransaction);
630+
631+
const transactionAfter = await con
632+
.getRepository(UserTransaction)
633+
.findOneByOrFail({
634+
id: transaction.id,
635+
});
636+
637+
expect(transactionAfter.id).toBe(transaction.id);
638+
expect(transactionAfter).toMatchObject({
639+
...transaction,
640+
valueIncFees: 42,
641+
updatedAt: expect.any(Date),
642+
});
643+
});
644+
645+
it('should throw if transaction has no id', async () => {
646+
const transaction = await con.getRepository(UserTransaction).create({
647+
processor: UserTransactionProcessor.Paddle,
648+
receiverId: 't-pc-2',
649+
status: UserTransactionStatus.Success,
650+
productId: null,
651+
senderId: 't-pc-1',
652+
value: 42,
653+
valueIncFees: 42,
654+
fee: 0,
655+
request: {},
656+
flags: {
657+
note: 'Test test!',
658+
},
659+
});
660+
661+
await expect(() =>
662+
njordCommon.purchaseCores({
663+
transaction,
664+
}),
665+
).rejects.toThrow(new Error('No transaction id'));
666+
});
667+
668+
it('should throw if transaction has product', async () => {
669+
const transaction = await con.getRepository(UserTransaction).save({
670+
processor: UserTransactionProcessor.Paddle,
671+
receiverId: 't-pc-2',
672+
status: UserTransactionStatus.Success,
673+
productId: '5329e56b-b121-47cb-9c3c-58c086c1542b',
674+
senderId: null,
675+
value: 42,
676+
valueIncFees: 42,
677+
fee: 0,
678+
request: {},
679+
flags: {
680+
note: 'Test test!',
681+
},
682+
});
683+
684+
await expect(() =>
685+
njordCommon.purchaseCores({
686+
transaction,
687+
}),
688+
).rejects.toThrow(
689+
new Error('Purchase cores transaction can not have product'),
690+
);
691+
});
692+
693+
it('should throw if transaction has sender', async () => {
694+
const transaction = await con.getRepository(UserTransaction).save({
695+
processor: UserTransactionProcessor.Paddle,
696+
receiverId: 't-pc-2',
697+
status: UserTransactionStatus.Success,
698+
productId: null,
699+
senderId: 't-pc-1',
700+
value: 42,
701+
valueIncFees: 42,
702+
fee: 0,
703+
request: {},
704+
flags: {
705+
note: 'Test test!',
706+
},
707+
});
708+
709+
await expect(() =>
710+
njordCommon.purchaseCores({
711+
transaction,
712+
}),
713+
).rejects.toThrow(
714+
new Error('Purchase cores transaction can not have sender'),
715+
);
716+
});
717+
718+
it('should sign request', async () => {
719+
const mockTransport = createMockNjordTransport();
720+
const mockedClient = createClient(Credits, mockTransport);
721+
const clientSpy = jest.spyOn(mockedClient, 'transfer');
722+
jest
723+
.spyOn(njordCommon, 'getNjordClient')
724+
.mockImplementation(() => mockedClient);
725+
726+
const transaction = await con.getRepository(UserTransaction).save({
727+
processor: UserTransactionProcessor.Paddle,
728+
receiverId: 't-pc-2',
729+
status: UserTransactionStatus.Success,
730+
productId: null,
731+
senderId: null,
732+
value: 42,
733+
valueIncFees: 42,
734+
fee: 0,
735+
request: {},
736+
flags: {
737+
note: 'Test test!',
738+
},
739+
});
740+
741+
await njordCommon.purchaseCores({
742+
transaction,
743+
});
744+
745+
expect(clientSpy).toHaveBeenCalledTimes(1);
746+
expect(clientSpy).toHaveBeenCalledWith(
747+
expect.objectContaining({
748+
idempotencyKey: transaction.id,
749+
transfers: expect.toBeArrayOfSize(1),
750+
}),
751+
expect.objectContaining({
752+
headers: expect.any(Headers),
753+
}),
754+
);
755+
expect(
756+
(clientSpy.mock.calls[0][1]!.headers as Headers).get('authorization'),
757+
).toStartWith('Bearer ');
758+
});
759+
});
760+
761+
describe('createNjordAuth', () => {
762+
beforeEach(async () => {
763+
jest.clearAllMocks();
764+
});
765+
766+
it('should create auth', async () => {
767+
const payload = new GetBalanceRequest({
768+
account: {
769+
userId: 't-cna-1',
770+
currency: Currency.CORES,
771+
},
772+
});
773+
774+
const result = await njordCommon.createNjordAuth(payload);
775+
776+
expect(result.headers).toBeInstanceOf(Headers);
777+
778+
const headers = result.headers as Headers;
779+
780+
expect(headers.get('authorization')).toStartWith('Bearer ');
781+
782+
const jwt = await verifyJwt(
783+
headers.get('authorization')!.replace('Bearer ', '')!,
784+
);
785+
786+
expect(jwt).toMatchObject({
787+
aud: 'Daily Staging',
788+
client_id: serviceClientId,
789+
iat: expect.any(Number),
790+
iss: 'Daily API Staging',
791+
message_hash:
792+
'87a33e6ae594147d8cd4d22b7b29f026f0ab4b45b66d9ff65ca7b456894f8871',
793+
});
794+
});
795+
});

0 commit comments

Comments
 (0)