Skip to content

Commit 24017b9

Browse files
Merge pull request #82 from shiftcode/#80-enhance-tests
#80 enhance tests
2 parents 85f098d + e18c4a4 commit 24017b9

22 files changed

+1183
-82
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// tslint:disable:no-empty
2+
3+
import { DateToNumberMapper } from '../mapper/custom'
4+
import { dynamoEasyConfig } from './dynamo-easy-config'
5+
import { updateDynamoEasyConfig } from './update-config.function'
6+
7+
describe('updateDynamoEasyConfig', () => {
8+
9+
it('should throw when providing invalid stuff', () => {
10+
expect(() => updateDynamoEasyConfig({ logReceiver: <any>null })).toThrow()
11+
expect(() => updateDynamoEasyConfig({ dateMapper: <any>null })).toThrow()
12+
})
13+
14+
it('should have defaults', () => {
15+
expect(dynamoEasyConfig.logReceiver).toBeDefined()
16+
expect(dynamoEasyConfig.dateMapper).toBeDefined()
17+
})
18+
19+
it('should work when providing valid stuff', () => {
20+
const myLogReceiver = () => {}
21+
const myDateMapper = { ...DateToNumberMapper }
22+
updateDynamoEasyConfig({
23+
logReceiver: myLogReceiver,
24+
dateMapper: myDateMapper,
25+
})
26+
expect(dynamoEasyConfig.logReceiver).toBe(myLogReceiver)
27+
expect(dynamoEasyConfig.dateMapper).toBe(myDateMapper)
28+
29+
})
30+
31+
})

src/config/update-config.function.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@ export function updateDynamoEasyConfig(config: Partial<Config>): void {
55
if (config.logReceiver !== undefined && typeof config.logReceiver !== 'function') {
66
throw new Error('Config.logReceiver has to be a function')
77
}
8+
if (config.dateMapper !== undefined && (config.dateMapper === null || typeof config.dateMapper.toDb !== 'function' || typeof config.dateMapper.fromDb !== 'function')) {
9+
throw new Error('Config.dateMapper must be an object of type MapperForType')
10+
}
811
Object.assign(dynamoEasyConfig, config)
912
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// tslint:disable:no-non-null-assertion
2+
import {
3+
ModelWithABunchOfIndexes, ModelWithAutogeneratedId,
4+
ModelWithGSI,
5+
ModelWithLSI,
6+
SimpleWithCompositePartitionKeyModel,
7+
SimpleWithPartitionKeyModel,
8+
} from '../../../test/models'
9+
import { INDEX_ACTIVE, INDEX_ACTIVE_CREATED_AT, INDEX_COUNT } from '../../../test/models/model-with-indexes.model'
10+
import { Metadata } from './metadata'
11+
12+
describe('metadata', () => {
13+
let metaDataPartitionKey: Metadata<SimpleWithPartitionKeyModel>
14+
let metaDataComposite: Metadata<SimpleWithCompositePartitionKeyModel>
15+
let metaDataLsi: Metadata<ModelWithLSI>
16+
let metaDataGsi: Metadata<ModelWithGSI>
17+
let metaDataIndexes: Metadata<ModelWithABunchOfIndexes>
18+
let metaDataUuid: Metadata<ModelWithAutogeneratedId>
19+
20+
beforeEach(() => {
21+
metaDataPartitionKey = new Metadata(SimpleWithPartitionKeyModel)
22+
metaDataComposite = new Metadata(SimpleWithCompositePartitionKeyModel)
23+
metaDataLsi = new Metadata(ModelWithLSI)
24+
metaDataGsi = new Metadata(ModelWithGSI)
25+
metaDataIndexes = new Metadata(ModelWithABunchOfIndexes)
26+
metaDataUuid = new Metadata(ModelWithAutogeneratedId)
27+
})
28+
29+
it('forProperty', () => {
30+
const forId = metaDataPartitionKey.forProperty('id')
31+
expect(forId).toBeDefined()
32+
expect(forId!.key).toBeDefined()
33+
expect(forId!.name).toBe('id')
34+
expect(forId!.typeInfo).toBeDefined()
35+
expect(forId!.typeInfo!.isCustom).toBeFalsy()
36+
})
37+
38+
it('getKeysWithUUID', () => {
39+
const uuid = metaDataUuid.getKeysWithUUID()
40+
expect(uuid.length).toBe(1)
41+
expect(uuid[0].key).toBeDefined()
42+
expect(uuid[0].key!.uuid).toBeTruthy()
43+
expect(uuid[0].name).toBe('id')
44+
45+
})
46+
47+
it('getPartitionKey', () => {
48+
expect(metaDataPartitionKey.getPartitionKey()).toEqual('id')
49+
expect(metaDataGsi.getPartitionKey(INDEX_ACTIVE)).toEqual('active')
50+
expect(metaDataIndexes.getPartitionKey(INDEX_COUNT)).toEqual('myId')
51+
expect(metaDataIndexes.getPartitionKey(INDEX_ACTIVE_CREATED_AT)).toEqual('active')
52+
53+
})
54+
55+
it('getSortKey', () => {
56+
expect(metaDataPartitionKey.getSortKey()).toBe(null)
57+
expect(metaDataComposite.getSortKey()).toBe('creationDate')
58+
expect(metaDataLsi.getSortKey(INDEX_ACTIVE)).toBe('active')
59+
expect(() => metaDataGsi.getSortKey(INDEX_ACTIVE)).toThrow()
60+
expect(metaDataIndexes.getSortKey(INDEX_ACTIVE_CREATED_AT)).toBe('createdAt')
61+
})
62+
63+
it('getIndexes', () => {
64+
expect(metaDataLsi.getIndexes()).toEqual([
65+
{ partitionKey: 'id', sortKey: 'active' },
66+
])
67+
expect(metaDataGsi.getIndexes()).toEqual([
68+
{ partitionKey: 'active' },
69+
])
70+
expect(metaDataIndexes.getIndexes()).toEqual([
71+
{ partitionKey: 'active', sortKey: 'createdAt' },
72+
{ partitionKey: 'myId', sortKey: 'count' },
73+
])
74+
})
75+
76+
it('getIndex', () => {
77+
expect(metaDataPartitionKey.getIndexes().length).toBe(0)
78+
expect(metaDataPartitionKey.getIndex('blub')).toBe(null)
79+
expect(metaDataIndexes.getIndex(INDEX_ACTIVE_CREATED_AT)).toEqual({
80+
partitionKey: 'active',
81+
sortKey: 'createdAt',
82+
})
83+
})
84+
85+
})
Lines changed: 85 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,97 @@
1+
import * as DynamoDB from 'aws-sdk/clients/dynamodb'
2+
import { of } from 'rxjs'
3+
import { getTableName } from '../../../test/helper'
4+
import { SimpleWithCompositePartitionKeyModel, SimpleWithPartitionKeyModel } from '../../../test/models'
15
import { Organization } from '../../../test/models/organization.model'
6+
import { Attributes } from '../../mapper'
7+
import { DynamoRx } from '../dynamo-rx'
28
import { BatchGetRequest } from './batch-get.request'
39

410
describe('batch get', () => {
511
let request: BatchGetRequest
612

7-
beforeEach(() => {
8-
request = new BatchGetRequest()
13+
14+
describe('params', () => {
15+
16+
beforeEach(() => request = new BatchGetRequest())
17+
18+
it('base params', () => {
19+
const params = request.params
20+
expect(params).toEqual({ RequestItems: {} })
21+
})
22+
23+
it('key', () => {
24+
request.forModel(Organization, ['idValue'])
25+
const params = request.params
26+
expect(params.RequestItems).toBeDefined()
27+
expect(params.RequestItems.Organization).toBeDefined()
28+
expect(params.RequestItems.Organization).toEqual({ Keys: [{ id: { S: 'idValue' } }] })
29+
})
930
})
1031

11-
it('base params', () => {
12-
const params = request.params
13-
expect(params).toEqual({ RequestItems: {} })
32+
33+
describe('forModel', () => {
34+
beforeEach(() => request = new BatchGetRequest())
35+
36+
it('should throw when same table is used 2 times', () => {
37+
request.forModel(SimpleWithPartitionKeyModel, ['idVal'])
38+
expect(() => request.forModel(SimpleWithPartitionKeyModel, ['otherVal'])).toThrow()
39+
})
40+
41+
it('should throw when providing null value ', () => {
42+
expect(() => request.forModel(SimpleWithPartitionKeyModel, [<any>null])).toThrow()
43+
})
44+
45+
it('should throw when sortKey is missing', () => {
46+
expect(() => request.forModel(SimpleWithCompositePartitionKeyModel, [{ partitionKey: 'idVal' }]))
47+
})
48+
49+
it('should throw when partitionKey is neither string nor object', () => {
50+
expect(() => request.forModel(SimpleWithCompositePartitionKeyModel, [<any>78]))
51+
expect(() => request.forModel(SimpleWithCompositePartitionKeyModel, [<any>true]))
52+
expect(() => request.forModel(SimpleWithCompositePartitionKeyModel, [<any>new Date()]))
53+
})
54+
1455
})
1556

16-
it('key', () => {
17-
request.forModel(Organization, ['idValue'])
18-
const params = request.params
19-
expect(params.RequestItems).toBeDefined()
20-
expect(params.RequestItems.Organization).toBeDefined()
21-
expect(params.RequestItems.Organization).toEqual({ Keys: [{ id: { S: 'idValue' } }] })
57+
58+
describe('should map the result items', () => {
59+
let batchGetItemsSpy: jasmine.Spy
60+
const jsItem: SimpleWithPartitionKeyModel = { id: 'idVal', age: 20 }
61+
const dbItem: Attributes<SimpleWithPartitionKeyModel> = {
62+
id: { S: 'idVal' },
63+
age: { N: '20' },
64+
}
65+
const sampleResponse: DynamoDB.BatchGetItemOutput = {
66+
Responses: {
67+
[getTableName(SimpleWithPartitionKeyModel)]: [dbItem],
68+
},
69+
UnprocessedKeys: {},
70+
}
71+
72+
beforeEach(() => {
73+
batchGetItemsSpy = jasmine.createSpy().and.returnValue(of(sampleResponse))
74+
const dynamoRx: DynamoRx = <any>{ batchGetItems: batchGetItemsSpy }
75+
request = new BatchGetRequest()
76+
Object.assign(request, { dynamoRx })
77+
request.forModel(SimpleWithPartitionKeyModel, ['idVal'])
78+
})
79+
80+
it('exec', async () => {
81+
const result = await request.exec().toPromise()
82+
expect(batchGetItemsSpy).toHaveBeenCalled()
83+
expect(result).toEqual({ [getTableName(SimpleWithPartitionKeyModel)]: [jsItem] })
84+
})
85+
86+
it('execFullResponse', async () => {
87+
const result = await request.execFullResponse().toPromise()
88+
expect(batchGetItemsSpy).toHaveBeenCalled()
89+
expect(result).toEqual({
90+
Responses: { [getTableName(SimpleWithPartitionKeyModel)]: [jsItem] },
91+
UnprocessedKeys: {},
92+
})
93+
})
94+
2295
})
96+
2397
})
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Observable } from 'rxjs'
2+
import { DEFAULT_SESSION_VALIDITY_ENSURER } from './default-session-validity-ensurer.const'
3+
4+
describe('DEFAULT_SESSION_VALIDITY_ENSURER', () => {
5+
it('should return an observable without value', async () => {
6+
expect(typeof DEFAULT_SESSION_VALIDITY_ENSURER === 'function').toBeTruthy()
7+
expect(DEFAULT_SESSION_VALIDITY_ENSURER() instanceof Observable).toBeTruthy()
8+
expect(await DEFAULT_SESSION_VALIDITY_ENSURER().toPromise()).toBeUndefined()
9+
})
10+
})

src/dynamo/dynamo-rx.spec.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// tslint:disable:no-empty
2+
// tslint:disable:no-unnecessary-callback-wrapper
3+
4+
import { Config, Credentials, DynamoDB } from 'aws-sdk'
5+
import { EMPTY, Observable } from 'rxjs'
6+
import { DEFAULT_SESSION_VALIDITY_ENSURER } from './default-session-validity-ensurer.const'
7+
import { DynamoRx } from './dynamo-rx'
8+
import { SessionValidityEnsurer } from './session-validity-ensurer.type'
9+
10+
describe('dynamo rx', () => {
11+
12+
describe('should call the validity ensurer before each call and return an observable', () => {
13+
let dynamoRx: DynamoRx
14+
let spyValidityEnsurer: SessionValidityEnsurer
15+
16+
beforeEach(() => {
17+
spyValidityEnsurer = jasmine.createSpy().and.returnValue(EMPTY)
18+
dynamoRx = new DynamoRx(spyValidityEnsurer)
19+
})
20+
21+
it('putItem', () => {
22+
expect(dynamoRx.putItem(<any>null) instanceof Observable).toBeTruthy()
23+
expect(spyValidityEnsurer).toHaveBeenCalled()
24+
})
25+
it('getItem', () => {
26+
expect(dynamoRx.getItem(<any>null) instanceof Observable).toBeTruthy()
27+
expect(spyValidityEnsurer).toHaveBeenCalled()
28+
})
29+
it('updateItem', () => {
30+
expect(dynamoRx.updateItem(<any>null) instanceof Observable).toBeTruthy()
31+
expect(spyValidityEnsurer).toHaveBeenCalled()
32+
})
33+
it('deleteItem', () => {
34+
expect(dynamoRx.deleteItem(<any>null) instanceof Observable).toBeTruthy()
35+
expect(spyValidityEnsurer).toHaveBeenCalled()
36+
})
37+
it('batchWriteItem', () => {
38+
expect(dynamoRx.batchWriteItem(<any>null) instanceof Observable).toBeTruthy()
39+
expect(spyValidityEnsurer).toHaveBeenCalled()
40+
})
41+
it('batchGetItems', () => {
42+
expect(dynamoRx.batchGetItems(<any>null) instanceof Observable).toBeTruthy()
43+
expect(spyValidityEnsurer).toHaveBeenCalled()
44+
})
45+
it('scan', () => {
46+
expect(dynamoRx.scan(<any>null) instanceof Observable).toBeTruthy()
47+
expect(spyValidityEnsurer).toHaveBeenCalled()
48+
})
49+
it('query', () => {
50+
const params: DynamoDB.QueryInput = {
51+
TableName: 'tableName',
52+
}
53+
expect(dynamoRx.query({ ...params, KeyConditionExpression: 'blub' }) instanceof Observable).toBeTruthy()
54+
expect(spyValidityEnsurer).toHaveBeenCalled()
55+
expect(() => dynamoRx.query(params)).toThrow()
56+
})
57+
it('makeRequest', () => {
58+
expect(dynamoRx.makeRequest(<any>null) instanceof Observable).toBeTruthy()
59+
expect(spyValidityEnsurer).toHaveBeenCalled()
60+
})
61+
})
62+
63+
it('should call makeRequest with the given params', async () => {
64+
const dynamoRx = new DynamoRx(DEFAULT_SESSION_VALIDITY_ENSURER)
65+
const makeRequest = jasmine.createSpy().and.returnValue({ promise: () => Promise.resolve(null) })
66+
Object.assign(dynamoRx, { dynamoDb: { makeRequest } })
67+
68+
await dynamoRx.makeRequest(<any>{ ok: true }).toPromise()
69+
expect(makeRequest).toHaveBeenCalled()
70+
expect(makeRequest.calls.mostRecent().args[0]).toEqual({ ok: true })
71+
})
72+
73+
it('should update the credentials', () => {
74+
const dynamoRx = new DynamoRx(DEFAULT_SESSION_VALIDITY_ENSURER)
75+
const credentials = new Credentials({ secretAccessKey: '', sessionToken: '', accessKeyId: '' })
76+
dynamoRx.updateAwsConfigCredentials(new Config({ credentials }))
77+
expect(dynamoRx.dynamoDb.config.credentials).toBe(credentials)
78+
})
79+
80+
})

0 commit comments

Comments
 (0)