@defra-fish/connectors-lib 1.63.0-rc.0 → 1.63.0-rc.10

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defra-fish/connectors-lib",
3
- "version": "1.63.0-rc.0",
3
+ "version": "1.63.0-rc.10",
4
4
  "description": "Shared connectors",
5
5
  "type": "module",
6
6
  "engines": {
@@ -46,5 +46,5 @@
46
46
  "node-fetch": "^2.7.0",
47
47
  "redlock": "^4.2.0"
48
48
  },
49
- "gitHead": "127bd6db86a97eb1b229f3de30e27046119ffca6"
49
+ "gitHead": "c4301461b148cbf244c1bb5c834521243ec0a534"
50
50
  }
@@ -1,6 +1,6 @@
1
1
  import { createDocumentClient } from '../documentclient-decorator'
2
2
  import { DynamoDB } from '@aws-sdk/client-dynamodb'
3
- import { DynamoDBDocument } from '@aws-sdk/lib-dynamodb'
3
+ import { DynamoDBDocument, QueryCommand, ScanCommand } from '@aws-sdk/lib-dynamodb'
4
4
 
5
5
  jest.mock('@aws-sdk/client-dynamodb')
6
6
  jest.mock('@aws-sdk/lib-dynamodb')
@@ -9,6 +9,7 @@ describe('document client decorations', () => {
9
9
  beforeAll(() => {
10
10
  jest.spyOn(global, 'setTimeout').mockImplementation(cb => cb())
11
11
  DynamoDBDocument.from.mockReturnValue({
12
+ send: jest.fn().mockResolvedValue({ Items: [], lastEvaluatedKey: false }),
12
13
  query: jest.fn().mockResolvedValue({ Items: [], lastEvaluatedKey: false }),
13
14
  scan: jest.fn().mockResolvedValue({ Items: [], lastEvaluatedKey: false }),
14
15
  batchWrite: jest.fn().mockResolvedValue({ UnprocessedItems: {} })
@@ -46,23 +47,30 @@ describe('document client decorations', () => {
46
47
  })
47
48
 
48
49
  describe.each`
49
- aggregateMethod | baseMethod
50
- ${'queryAllPromise'} | ${'query'}
51
- ${'scanAllPromise'} | ${'scan'}
52
- `('$aggregateMethod', ({ aggregateMethod, baseMethod }) => {
50
+ aggregateMethod | commandType
51
+ ${'queryAllPromise'} | ${QueryCommand}
52
+ ${'scanAllPromise'} | ${ScanCommand}
53
+ `('$aggregateMethod', ({ aggregateMethod, commandType }) => {
53
54
  it('is added to document client', () => {
54
55
  const docClient = createDocumentClient()
55
56
  expect(docClient[aggregateMethod]).toBeDefined()
56
57
  })
57
58
 
58
- it(`passes arguments provided for ${aggregateMethod} to ${baseMethod}`, async () => {
59
+ it(`passes arguments provided for ${aggregateMethod} to ${commandType.name}`, async () => {
59
60
  const params = { TableName: 'TEST', KeyConditionExpression: 'id = :id', ExpressionAttributeValues: { ':id': 1 } }
60
61
  const docClient = createDocumentClient()
61
62
  await docClient[aggregateMethod](params)
62
- expect(docClient[baseMethod]).toHaveBeenCalledWith(params)
63
+ expect(commandType).toHaveBeenCalledWith(params)
63
64
  })
64
65
 
65
- it(`calls ${baseMethod} repeatedly until LastEvaluatedKey evaluates to false, concatenating all returned items`, async () => {
66
+ it(`passes created command ${commandType.name} to docClient.send`, async () => {
67
+ const docClient = createDocumentClient()
68
+ await docClient[aggregateMethod]()
69
+ const [command] = commandType.mock.instances
70
+ expect(docClient.send).toHaveBeenCalledWith(command)
71
+ })
72
+
73
+ it('calls send repeatedly until LastEvaluatedKey evaluates to false, concatenating all returned items', async () => {
66
74
  const expectedItems = [
67
75
  { id: 1, data: Symbol('data1') },
68
76
  { id: 2, data: Symbol('data2') },
@@ -71,7 +79,7 @@ describe('document client decorations', () => {
71
79
  { id: 5, data: Symbol('data5') }
72
80
  ]
73
81
  const docClient = createDocumentClient()
74
- docClient[baseMethod]
82
+ docClient.send
75
83
  .mockResolvedValueOnce({ Items: expectedItems.slice(0, 2), LastEvaluatedKey: true })
76
84
  .mockResolvedValueOnce({ Items: expectedItems.slice(2, 4), LastEvaluatedKey: true })
77
85
  .mockResolvedValueOnce({ Items: expectedItems.slice(4), LastEvaluatedKey: false })
@@ -79,13 +87,12 @@ describe('document client decorations', () => {
79
87
  expect(actualItems).toEqual(expectedItems)
80
88
  })
81
89
 
82
- it(`whilst concatenating ${baseMethod} results, passes ExclusiveStartKey param`, async () => {
90
+ it(`whilst concatenating ${commandType.name} results, passes ExclusiveStartKey param`, async () => {
83
91
  const expectedKey = Symbol('🔑')
84
92
  const docClient = createDocumentClient()
85
- docClient[baseMethod].mockResolvedValueOnce({ Items: [], LastEvaluatedKey: expectedKey }).mockResolvedValueOnce({ Items: [] })
93
+ docClient.send.mockResolvedValueOnce({ Items: [], LastEvaluatedKey: expectedKey }).mockResolvedValueOnce({ Items: [] })
86
94
  await docClient[aggregateMethod]()
87
- expect(docClient[baseMethod]).toHaveBeenNthCalledWith(
88
- 2,
95
+ expect(commandType).toHaveBeenLastCalledWith(
89
96
  expect.objectContaining({
90
97
  ExclusiveStartKey: expectedKey
91
98
  })
@@ -95,7 +102,7 @@ describe('document client decorations', () => {
95
102
  it("omits ExclusiveStartKey if previous LastEvaluatedKey isn't available", async () => {
96
103
  const docClient = createDocumentClient()
97
104
  await docClient[aggregateMethod]()
98
- expect(docClient[baseMethod]).toHaveBeenNthCalledWith(
105
+ expect(docClient.send).toHaveBeenNthCalledWith(
99
106
  1,
100
107
  expect.not.objectContaining({
101
108
  ExclusiveStartKey: expect.anything()
@@ -746,4 +746,44 @@ describe('sales-api-connector', () => {
746
746
  await expect(salesApi.cancelRecurringPayment('id')).rejects.toThrow('Internal Server Error')
747
747
  })
748
748
  })
749
+
750
+ describe('retrieveStagedTransaction', () => {
751
+ describe.each([['id'], ['abc-123']])("Retrieving staged transaction id '%s'", id => {
752
+ beforeEach(() => {
753
+ fetch.mockReturnValue({
754
+ ok: true,
755
+ status: 200,
756
+ statusText: 'OK',
757
+ text: async () => JSON.stringify({ id })
758
+ })
759
+ })
760
+
761
+ it('calls the endpoint with the correct parameters', async () => {
762
+ await salesApi.retrieveStagedTransaction(id)
763
+
764
+ expect(fetch).toHaveBeenCalledWith(`http://0.0.0.0:4000/retrieveStagedTransaction/${id}`, {
765
+ method: 'get',
766
+ headers: expect.any(Object),
767
+ timeout: 20000
768
+ })
769
+ })
770
+
771
+ it('returns the expected response data', async () => {
772
+ const processedResult = await salesApi.retrieveStagedTransaction(id)
773
+
774
+ expect(processedResult).toEqual({ id })
775
+ })
776
+ })
777
+
778
+ it('throws an error on non-2xx response', async () => {
779
+ fetch.mockReturnValue({
780
+ ok: false,
781
+ status: 500,
782
+ statusText: 'Internal Server Error',
783
+ text: async () => 'Server Error'
784
+ })
785
+
786
+ await expect(salesApi.retrieveStagedTransaction('id')).rejects.toThrow('Internal Server Error')
787
+ })
788
+ })
749
789
  })
@@ -1,6 +1,6 @@
1
1
  import db from 'debug'
2
2
  import { DynamoDB } from '@aws-sdk/client-dynamodb'
3
- import { DynamoDBDocument } from '@aws-sdk/lib-dynamodb'
3
+ import { DynamoDBDocument, QueryCommand, ScanCommand } from '@aws-sdk/lib-dynamodb'
4
4
  const debug = db('connectors:aws')
5
5
 
6
6
  export const createDocumentClient = options => {
@@ -13,23 +13,24 @@ export const createDocumentClient = options => {
13
13
  })
14
14
 
15
15
  // Support for large query/scan operations which return results in pages
16
- const wrapPagedDocumentClientOperation = operationName => {
16
+ const wrapPagedDocumentClientOperation = CommandType => {
17
17
  return async params => {
18
18
  const items = []
19
19
  let lastEvaluatedKey = null
20
20
  do {
21
- const response = await docClient[operationName]({
21
+ const command = new CommandType({
22
22
  ...params,
23
23
  ...(lastEvaluatedKey && { ExclusiveStartKey: lastEvaluatedKey })
24
24
  })
25
+ const response = await docClient.send(command)
25
26
  lastEvaluatedKey = response.LastEvaluatedKey
26
27
  response.Items && items.push(...response.Items)
27
28
  } while (lastEvaluatedKey)
28
29
  return items
29
30
  }
30
31
  }
31
- docClient.queryAllPromise = wrapPagedDocumentClientOperation('query')
32
- docClient.scanAllPromise = wrapPagedDocumentClientOperation('scan')
32
+ docClient.queryAllPromise = wrapPagedDocumentClientOperation(QueryCommand)
33
+ docClient.scanAllPromise = wrapPagedDocumentClientOperation(ScanCommand)
33
34
 
34
35
  /**
35
36
  * Handles batch writes which may return UnprocessedItems. If UnprocessedItems are returned then they will be retried with exponential backoff
@@ -319,3 +319,14 @@ export const processRPResult = async (transactionId, paymentId, createdDate) =>
319
319
  export const cancelRecurringPayment = async id => {
320
320
  return exec2xxOrThrow(call(new URL(`/cancelRecurringPayment/${id}`, urlBase), 'get'))
321
321
  }
322
+
323
+ /**
324
+ * Retrieve a staged transaction
325
+ *
326
+ * @param id
327
+ * @returns {Promise<*>}
328
+ * @throws on a non-2xx response
329
+ */
330
+ export const retrieveStagedTransaction = async id => {
331
+ return exec2xxOrThrow(call(new URL(`/retrieveStagedTransaction/${id}`, urlBase), 'get'))
332
+ }