LoginSignup
9
5

More than 5 years have passed since last update.

serverless × node.js × DynamoDB チートシート〜serverless.yml 定義例、DynamoDB Client 使用例、テスト記述例 〜

Last updated at Posted at 2018-05-07

こんにちは最近、 serverless ✕ DynamoDB ✕ node.js の組み合わせでのサービス開発を
自分の中のメイン方式にするべく習得中です。

2週間くらい経つと学んだことを忘れてしまうので、
重宝した参考記事と書いた設定/コードを備忘のため、チートシートとしてまとめます。

本記事で書くこと

  • ①serverless.yml でのDynamoDBテーブル定義例
  • ②node.jsのAWS SDK「DynamoDB Client」の使用例
  • ③node.js ローカル環境でのテスト記述例

前提: 題材としたシステムについて

家族とシェアしている Google Photos の写真をLINE Botで検索、
懐かしの思い出の写真を自動投稿 する、ほのぼの系Botを作っています。

Room/Album/Photoの3つのテーブルを例に説明します。

テーブル:「Room」 BOTとの会話部屋情報を管理

  • PrimaryKey は roomId
  • SortKey はなしです。
room.json
  {
    "roomId": "room1",
    "albumKeyword": "keyword1",
    "roomType": "user",
    "users": [{
        "userId": "user1",
        "googleRefreshToken": "token1"
    }]
  }

テーブル:「Album」 写真アルバム情報を管理

  • PrimaryKey は roomId
  • SortKey は albumId
album.json
{
    "roomId": "room1",
    "albumId": "album1",
    "albumTitle": "AlbumName1 keyword1",
    "numPhotos": 3,
    "status": "WAITING_UPDATE"
}

テーブル:「Photo」 写真情報を管理

  • PrimaryKey は roomId
  • SortKey が albumIKey (albumId と photoId の複合キー)
    • albumIDをキーに写真検索したかったので。アルバム削除時に写真も削除したいため。
  • LocalSecondaryIndexに date を指定
    • 日付で写真検索したかったので。
photo.json
{
    "roomId": "room1",
    "albumIdKey": "album1-photo1",
    "date": "20170201",
    "timestamp": "1485955237000",
    "type": "image/jpeg",
    "url": "https://lh3.googleusercontent.com/xxx/xxx/xxx/a1-p1.JPG"
}

①serverless.yml でのDynamoDBテーブル定義例

参考記事

以下の記事にお世話になりました。

書いた設定ファイル

serverless.yml
# ...略...
custom:
  defaultStage: dev
  tableNameRoom: '${self:service}-Room-${self:provider.stage}'
  tableNameAlbum: '${self:service}-Album-${self:provider.stage}'
  tableNamePhoto: '${self:service}-Photo-${self:provider.stage}'
  dynamodb:
    start:
      port: 8000
      inMemory: true
      migrate: true
      seed: true
    seed:
      development:
        sources:
          - table: ${self:custom.tableNameRoom}
            sources: [./migrations/rooms.json]
          - table: ${self:custom.tableNameAlbum}
            sources: [./migrations/albums.json]
          - table: ${self:custom.tableNamePhoto}
            sources: [./migrations/photos.json]

resources:
  Resources:
    RoomTable:
      Type: 'AWS::DynamoDB::Table'
      Properties:
        TableName: ${self:custom.tableNameRoom}
        AttributeDefinitions:
          - AttributeName: roomId
            AttributeType: S
        KeySchema:
          - AttributeName: roomId
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
    AlbumTable:
      Type: 'AWS::DynamoDB::Table'
      Properties:
        TableName: ${self:custom.tableNameAlbum}
        AttributeDefinitions:
          - AttributeName: roomId
            AttributeType: S
          - AttributeName: albumId
            AttributeType: S
        KeySchema:
          - AttributeName: roomId
            KeyType: HASH
          - AttributeName: albumId
            KeyType: RANGE
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
    PhotoTable:
      Type: 'AWS::DynamoDB::Table'
      Properties:
        TableName: ${self:custom.tableNamePhoto}
        AttributeDefinitions:
          - AttributeName: roomId
            AttributeType: S
          - AttributeName: albumIdKey
            AttributeType: S
          - AttributeName: date
            AttributeType: S
        KeySchema:
          - AttributeName: roomId
            KeyType: HASH
          - AttributeName: albumIdKey
            KeyType: RANGE
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
        LocalSecondaryIndexes:
          - IndexName: dateIndex
            KeySchema:
              - AttributeName: roomId
                KeyType: HASH
              - AttributeName: date
                KeyType: RANGE
            Projection:
              ProjectionType: ALL

②node.jsのAWS SDK「DynamoDB Client」の使い方

参考記事

書いたコード (table毎のDynamoDB操作をモジュール化)

dynamodb.js
'use strict';

const AWS = require('aws-sdk');


class DynamoDBClient {

    constructor(options) {
        this.docClient = new AWS.DynamoDB.DocumentClient(options);
        this.tableNameRoom = options.tableNameRoom;
        this.tableNameAlbum = options.tableNameAlbum;
        this.tableNamePhoto = options.tableNamePhoto;
    }


    async scanRoom() {
        const params = {
            TableName: this.tableNameRoom
        };
        return this.docClient.scan(params).promise();
    }


    async getRoomItem(roomId) {
        const params = {
            TableName: this.tableNameRoom,
            Key: {
                roomId: roomId
            }
        };
        return this.docClient.get(params).promise();
    }


    async getAlbums(roomId) {
        const params = {
            TableName: this.tableNameAlbum,
            KeyConditionExpression: '#pk = :pk_value',
            ExpressionAttributeNames: {
                '#pk': 'roomId',
            },
            ExpressionAttributeValues: {
                ':pk_value': roomId,
            }
        };
        return this.docClient.query(params).promise();
    }


    async getAlbumItem(roomId, albumId) {
        const params = {
            TableName: this.tableNameAlbum,
            Key: {
                roomId: roomId,
                albumId: albumId
            }
        };
        return this.docClient.get(params).promise();
    }


    async getPhotosByAlbumId(roomId, albumId) {
        const params = {
            TableName: this.tableNamePhoto,
            KeyConditionExpression: '#pk = :pk_value AND begins_with(#sk, :sk_value)',
            ExpressionAttributeNames: {
                '#pk': 'roomId',
                '#sk': 'albumIdKey'
            },
            ExpressionAttributeValues: {
                ':pk_value': roomId,
                ':sk_value': albumId
            }
        };
        return this.docClient.query(params).promise();
    }


    async getPhotosByDate(roomId, dateStr) {
        const params = {
            TableName: this.tableNamePhoto,
            IndexName: 'dateIndex',
            KeyConditionExpression: '#pk = :pk_value AND begins_with(#sk, :sk_value)',
            ExpressionAttributeNames: {
                '#pk': 'roomId',
                '#sk': 'date'
            },
            ExpressionAttributeValues: {
                ':pk_value': roomId,
                ':sk_value': dateStr
            }
        };
        return this.docClient.query(params).promise();
    };


    async putRoomItem(room) {
        const params = {
            TableName: this.tableNameRoom,
            Item: room
        };
        return this.docClient.put(params).promise();
    }


    async updateRoomItemUsers(roomId, users) {
        const params = {
            TableName: this.tableNameRoom,
            Key: {
                roomId: roomId
            },
            ExpressionAttributeNames: {
                '#users': 'users'
            },
            ExpressionAttributeValues: {
                ':newUsers': users
            },
            UpdateExpression: 'SET #users = :newUsers'
        };
        return this.docClient.update(params).promise();
    }


    async putAlbumItem(album) {
        const params = {
            TableName: this.tableNameAlbum,
            Item: album
        };
        return this.docClient.put(params).promise();
    }


    async putPhotoItem(photo) {
        const params = {
            TableName: this.tableNamePhoto,
            Item: photo
        };
        return this.docClient.put(params).promise();
    }


    async deleteRoomItem(roomId) {
        const params = {
            TableName: this.tableNameRoom,
            Key: {
                roomId: roomId
            },
        };
        return this.docClient.delete(params).promise();
    }


    async deleteAlbumItem(roomId, albumId) {
        const params = {
            TableName: this.tableNameAlbum,
            Key: {
                roomId: roomId,
                albumId: albumId
            }
        };
        return this.docClient.delete(params).promise();
    }


    async deletePhotoItem(roomId, albumIdKey) {
        const params = {
            TableName: this.tableNamePhoto,
            Key: {
                roomId: roomId,
                albumIdKey: albumIdKey
            }
        };
        return this.docClient.delete(params).promise();
    }
}

module.exports = DynamoDBClient;

③node.js ローカル環境でのテストの書き方

参考記事

書いたコード (Dynamo.jsに対するテストコード)

dynamodb-test.js
'use strict';

const _ = require('underscore');
const chai = require('chai');
const assert = chai.assert;

const TABLE_NAME_ROOM = 'YOUR_SERVICE_NAME-Room-dev';
const TABLE_NAME_ALBUM = 'YOUR_SERVICE_NAME-Album-dev';
const TABLE_NAME_PHOTO = 'YOUR_SERVICE_NAME-Photo-dev';

const DynamoClient = require('./../../lib/dynamodb');
const client = new DynamoClient({
    region: 'localhost',
    endpoint: 'http://localhost:8000',
    tableNameRoom: TABLE_NAME_ROOM,
    tableNameAlbum: TABLE_NAME_ALBUM,
    tableNamePhoto: TABLE_NAME_PHOTO
});


describe('check DynamoDB Client using local DynamoDB service', () => {


    it('should get all room items from local DynamoDB by scanRoom', async() => {
        const result = await client.scanRoom();
        assert.equal(result.Count, 2);

        const rooms = require('./../../migrations/rooms.json');
        const roomIds = rooms.map(room => room.roomId);
        const albumKeywords = rooms.map(room => room.albumKeyword);
        for (const item of result.Items) {
            assert.include(roomIds, item.roomId);
            assert.include(albumKeywords, item.albumKeyword);
        }
    });


    it('should get a room item from local DynamoDB by getRoomItem', async() => {
        const result1 = await client.getRoomItem('room1');
        assert.equal(result1.Item.albumKeyword, 'keyword1');
        assert.equal(result1.Item.roomType, 'user');
        assert.lengthOf(result1.Item.users, 1);

        const result2 = await client.getRoomItem('room2');
        assert.equal(result2.Item.albumKeyword, 'keyword2');
        assert.equal(result2.Item.roomType, 'room');
        assert.lengthOf(result2.Item.users, 3);

        // Pattern of No result.
        const result3 = await client.getRoomItem('room3');
        assert.deepStrictEqual(result3, {});
    });


    it('should get album items associated roomId from local DynamoDB by getAlbums', async() => {
        const result1 = await client.getAlbums('room1');
        assert.equal(result1.Count, 2);
        const albumIds = result1.Items.map(item => item.albumId);
        assert.include(albumIds, 'album1');
        assert.include(albumIds, 'album2');

        const result2 = await client.getAlbums('room2');
        assert.equal(result2.Count, 1);
        assert.equal(result2.Items[0].albumId, 'album2');

        // Pattern of No result.
        const result3 = await client.getAlbums('room3');
        assert.equal(result3.Count, 0);
    });


    it('should get a album item from local DynamoDB by getAlbumItem', async() => {
        const result1 = await client.getAlbumItem('room1', 'album1');
        assert.equal(result1.Item.numPhotos, 3);
        assert.equal(result1.Item.albumTitle, 'AlbumName1 keyword1');
        assert.equal(result1.Item.status, 'WAITING_UPDATE');

        const result2 = await client.getAlbumItem('room1', 'album2');
        assert.equal(result2.Item.numPhotos, 2);
        assert.equal(result2.Item.albumTitle, 'AlbumName2 keyword2');
        assert.equal(result2.Item.status, 'UPDATED');

        const result3 = await client.getAlbumItem('room2', 'album2');
        assert.equal(result3.Item.roomId, 'room2');
        assert.equal(result3.Item.albumId, 'album2');

        // Pattern of No result.
        const result4 = await client.getAlbumItem('room2', 'album1');
        assert.deepStrictEqual(result4, {});
    });

    it('should get photos from local DynamoDB by getPhotosByAlbumId', async() => {
        const result1 = await client.getPhotosByAlbumId('room1', 'album1');
        assert.equal(result1.Count, 3);
        const result1AlbumIdKeys = result1.Items.map(item => item.albumIdKey);
        assert.include(result1AlbumIdKeys, 'album1-photo1');
        assert.include(result1AlbumIdKeys, 'album1-photo2');
        assert.include(result1AlbumIdKeys, 'album1-photo3');

        const result2 = await client.getPhotosByAlbumId('room1', 'album2');
        assert.equal(result2.Count, 2);
        const result2AlbumIdKeys = result2.Items.map(item => item.albumIdKey);
        assert.include(result2AlbumIdKeys, 'album2-photo1');
        assert.include(result2AlbumIdKeys, 'album2-photo2');

        const result3 = await client.getPhotosByAlbumId('room2', 'album2');
        assert.equal(result3.Count, 1);
        assert.equal(result3.Items[0].albumIdKey, 'album2-photo1');
        assert.equal(result3.Items[0].url, 'https://lh3.googleusercontent.com/xxx/xxx/xxx/a2-p1.JPG');

        // Pattern of No result.
        const result4 = await client.getPhotosByAlbumId('room1', 'album3');
        assert.equal(result4.Count, 0);
    });


    it('should get photos from local DynamoDB by getPhotosByDate', async() => {
        const result1 = await client.getPhotosByDate('room1', '20170201');
        assert.equal(result1.Count, 1);
        assert.equal(result1.Items[0].albumIdKey, 'album1-photo1');

        const result2 = await client.getPhotosByDate('room1', '20170205');
        assert.equal(result2.Count, 3);
        const albumIdKeys = result2.Items.map(item => item.albumIdKey);
        assert.include(albumIdKeys, 'album1-photo3');
        assert.include(albumIdKeys, 'album2-photo1');
        assert.include(albumIdKeys, 'album2-photo2');

        const result3 = await client.getPhotosByDate('room2', '20170205');
        assert.equal(result3.Count, 1);
        assert.equal(result3.Items[0].albumIdKey, 'album2-photo1');

        // Pattern of No result.
        const result4 = await client.getPhotosByDate('room1', '20170202');
        assert.equal(result4.Count, 0);
    });


    it('should put a room item to local DynamoDB by putRoomItem', async() => {
        // new item
        const data = {
            roomId: 'newRoom1',
            albumKeyword: 'newKeyword1',
            roomType: 'room',
            users: [
                {userId: 'user1', googleRefreshToken: 'token1'}
            ]
        };
        // refresh the table
        await client.deleteRoomItem(data.roomId);

        // confirm empty result before put the item
        const emptyResult = await client.getRoomItem(data.roomId);
        assert.deepStrictEqual(emptyResult, {});

        // put the new item
        await client.putRoomItem(data);
        const afterPutResult = await client.getRoomItem(data.roomId);
        assert.deepStrictEqual(afterPutResult.Item, data);

        // update the item of users
        const newUsers = data.users;
        newUsers.push({userId: 'new-user1'});
        await client.updateRoomItemUsers(data.roomId, newUsers);
        const afterUpdateResult2 = await client.getRoomItem(data.roomId);
        assert.deepStrictEqual(afterUpdateResult2.Item.users, newUsers);

        // delete the item for re-test
        await client.deleteRoomItem(data.roomId);
    });


    it('should put a room items to local DynamoDB by putAlbumItem', async() => {
        // new item
        const dataRoomId = 'newRoom1';
        const dataAlbumId = 'newAlbum1';
        const data = {
            roomId: dataRoomId,
            albumId: dataAlbumId,
            albumTitle: 'AlbumName1 newKeyword1',
            numPhotos: 1,
            status: 'WAITING_UPDATE'
        };

        // refresh the table
        await client.deleteAlbumItem(dataRoomId, dataAlbumId);

        // confirm empty result before put the item
        const emptyResult = await client.getAlbumItem(dataRoomId, dataAlbumId);
        assert.deepStrictEqual(emptyResult, {});

        // put the new item
        await client.putAlbumItem(data);
        const afterPutResult = await client.getAlbumItem(dataRoomId, dataAlbumId);
        assert.deepStrictEqual(afterPutResult.Item, data);

        // update the item
        data.status = 'UPDATED';
        await client.putAlbumItem(data);
        const afterUpdateResult = await client.getAlbumItem(dataRoomId, dataAlbumId);
        assert.deepStrictEqual(afterUpdateResult.Item, data);

        // delete the item for re-test
        await client.deleteAlbumItem(dataRoomId, dataAlbumId);
    });


    it('should put a photo items to local DynamoDB by putPhotoItem', async() => {
        // new item
        const dataRoomId = 'newRoom1';
        const dataAlbumId = 'newAlbum1';
        const dataPhotoId = 'newPhoto1';
        const dataAlbumIdKey = `${dataAlbumId}-${dataPhotoId}`;

        const data = {
            roomId: dataRoomId,
            albumIdKey: dataAlbumIdKey,
            date: '20170203',
            timestamp: '1486076126000',
            type: 'image/jpeg',
            url: `https://lh3.googleusercontent.com/xxx/xxx/xxx/${dataAlbumIdKey}.JPG`
        };

        // refresh the table
        await client.deletePhotoItem(dataRoomId, dataAlbumIdKey);

        // confirm empty result before put the item
        const emptyResult = await client.getPhotosByAlbumId(dataRoomId, dataAlbumIdKey);
        assert.equal(emptyResult.Count, 0);

        // put the new item
        await client.putPhotoItem(data);
        const afterPutResult = await client.getPhotosByAlbumId(dataRoomId, dataAlbumIdKey);
        assert.equal(afterPutResult.Count, 1);
        assert.deepStrictEqual(afterPutResult.Items[0], data);

        // delete the item for re-test
        await client.deletePhotoItem(dataRoomId, dataAlbumIdKey);
    });

});

その他テストコード (SQS)

実行コード (SQS)

sqs.js
'use strict';

const _ = require('underscore');
const AWS = require('aws-sdk');
const dateUtil = require('./date-util.js');


const MAX_NUMBER_OF_RECEIVE_MESSAGES = 10;
const RECEIVE_VISIBILITY_TIMEOUT = 10;


const newMessageTemplate = (roomId, photo) => {
    return {
        messageType: 'UPDATE',
        roomId: roomId,
        albumIdKey: `${photo.album_id}-${photo.id}`,
        date: dateUtil.getDay(parseInt(photo.timestamp)),
        timestamp: photo.timestamp,
        type: photo.content.type,
        url: photo.content.src
    };
};


const deleteMessageTemplate = (roomId, photo) => {
    return {
        messageType: 'DELETE',
        roomId: roomId,
        albumIdKey: photo.albumIdKey,
    };
};


const completeMessageTemplate = (roomId, albumId) => {
    return {
        messageType: 'COMPLETE',
        roomId: roomId,
        albumId: albumId,
    };
};


class SQSClient {

    constructor(options) {
        this.sqs = new AWS.SQS(options);
        this.defaultParams = {
            QueueUrl: options.QueueUrl
        };
    }

    // PRIVATE METHOD
    enqueue(message) {
        const params = _.extend({MessageBody: JSON.stringify(message)}, this.defaultParams);
        return this.sqs.sendMessage(params).promise();
    }


    enqueueNewMessage(roomId, photo) {
        return this.enqueue(newMessageTemplate(roomId, photo));
    }


    enqueueDeleteMessage(roomId, photo) {
        return this.enqueue(deleteMessageTemplate(roomId, photo));
    }


    enqueueCompleteMessage(roomId, albumId) {
        return this.enqueue(completeMessageTemplate(roomId, albumId));
    }


    // PRIVATE METHOD
    async receiveMessageHandler(message, handler) {
        await handler(message);
        const params = _.extend({ReceiptHandle: message.ReceiptHandle}, this.defaultParams);
        return this.sqs.deleteMessage(params).promise();
    }


    async receiveMessages(handler) {
        const params = _.extend({
            MaxNumberOfMessages: MAX_NUMBER_OF_RECEIVE_MESSAGES,
            VisibilityTimeout: RECEIVE_VISIBILITY_TIMEOUT
        }, this.defaultParams);
        const response = await this.sqs.receiveMessage(params).promise();
        if (!response.Messages) return;
        return Promise.all(response.Messages.map(message => this.receiveMessageHandler(message, handler)));
    }

}

module.exports = SQSClient;

テストコード (SQS)

sqs-test.js
'use strict';

const _ = require('underscore');
const chai = require('chai');
const assert = chai.assert;
const proxyquire = require('proxyquire');


// DUMMY RESPONSE of AWS.SQS.sendMessage
const dummyResponseSendMessage = {
    ResponseMetadata: {RequestId: 'e41cc172-b12c-51b1-851f-9218a2a3ec24'},
    MD5OfMessageBody: 'e3c27b4365ce1fb9f86d32e64102a304',
    MessageId: '2a669cd3-983d-44d0-9761-d60fd3ba8fa5'
};


// DUMMY RESPONSE of AWS.SQS.receiveMessage
const dummyResponseReceiveMessage = {
    ResponseMetadata: {RequestId: '74f00447-e65c-5b57-aab5-572df5c2a200'},
    Messages: [
        {
            MessageId: '2a669cd3-983d-44d0-9761-d60fd3ba8fa5',
            ReceiptHandle: 'AQEBQLUDuMah/rsKknwzxP9gEOv+sc8I9dC57v2QcgNZ/N0qSHlcyLw+W7H5gSF+4FtJ6KAv1w1wp7/Aoe48/vPGRDoORkS4JOMzJEqC2Ql+jh8SmKfpxAw8hNQmOEcLJpDKp14i3thXyKT0Ad9uQHmg7T06zDbl0I9LqIja9D52wqWXKElEPruL5ZVArxT46QmXk0u6bsPQePHXCculvba0Gy7MW0xEXMy5yIWXDZL5CYmLZjQ5pQvuyVohp0L0kFw/152eKemu3vPENnGYB4kS3rC8heu6/QMn3+ODqreQHcO7C7w3ciiSvACUKLnePeJJwY3XUXKBMnf+OnuJRUrXOnTtpsuShqALYgGOoR/sYBWN/aqLJsT0syFhIMByPLXXm9X5St4m/WshwmkgqFZdD+kPAQTVdpIXm3xmenDjjKU=',
            MD5OfBody: 'e3c27b4365ce1fb9f86d32e64102a304',
            Body: '{"messageType":"DELETE","roomId":"room-1","albumKey":"album-1-photo-1"}'
        },
        {
            MessageId: 'fe1b2e28-9200-48b2-b2ff-5a82be53c359',
            ReceiptHandle: 'AQEBwakNhLL9MPSsSml32FtjNUrG6aQeVozaWSRQYeH/pUT/+FG2L6DovCVwC+vMps6OROoDwLWIVTXaMMK0prqpJtm+NzLXaN+qvch9+juaEeHfcvsuI+xU4NRylgfd6fb5tsDKT0t2ThRLB8Z01+8GbsHjIX6BEs3nfR/p+4upt3j0KTWJKZVfh88/G/DaofLtHGNnlq3A2dDyFkXZ4/JjIQf5C/ZFzBqzUtFxX6Lx/AMLMDXFazbd6uI2kVmUsyeS4WIxx7vDYH7C2iZxUAH36B6QvfSqtWTzVNVzIKSHZxMpbXrWzp6CkJWuf53XNJ50JZf0bKIkHum3Tq0S5gsWnZQ6Sub7JHRkdU2OWzHar7Ebdwhws8aKBzQ6ENgT981HYLwd95M0yyP64Z55l06GtTBkSaGIZZekvN15hpqiw8g=',
            MD5OfBody: 'd822bfa70dba0a6029f3a156479f7bf8',
            Body: '{"messageType":"COMPLETE","roomId":"room-1","albumId":"album-1"}'
        }]
};


// DUMMY RESPONSE of AWS.SQS.deleteMessage
const dummyResponseDeleteMessage = {
    ResponseMetadata: {RequestId: 'c3824af3-cf44-5dc7-bc7f-1999dcda3f3d'}
};

// AWS.SQS Stub for proxyquire
const awsStub = {
    SQS: class {
        constructor(options) {
        }

        sendMessage(params) {
            return {
                promise: async() => {
                    return dummyResponseSendMessage
                }
            };
        }

        receiveMessage(params) {
            return {
                promise: async() => {
                    return dummyResponseReceiveMessage
                }
            };
        }

        deleteMessage(params) {
            return {
                promise: async() => {
                    return dummyResponseDeleteMessage
                }
            };
        }
    }
};


const SQS = proxyquire('./../../lib/sqs', {
    'aws-sdk': awsStub
});
const sqsClient = new SQS({QueueUrl: 'http://hogehoge.com'});


describe('check SQS Client using proxyquire', () => {
        const roomId = 'room-1';
        const photo = {
            timestamp: '1525680256000',
            id: 'photo-1',
            album_id: 'album-1',
            content: {
                type: 'photo-type',
                url: 'photo-url'
            }
        };

        it('should call enqueueNewMessage', async() => {
            const res = await sqsClient.enqueueNewMessage(roomId, photo);
            assert.deepEqual(dummyResponseSendMessage, res);
        });

        it('should call enqueueDeleteMessage', async() => {
            const res = await sqsClient.enqueueDeleteMessage(roomId, photo);
            assert.deepEqual(dummyResponseSendMessage, res);
        });

        it('should call enqueueCompleteMessage', async() => {
            const res = await sqsClient.enqueueCompleteMessage(roomId, photo.album_id);
            assert.deepEqual(dummyResponseSendMessage, res);
        });

        it('should call receiveMessages', async() => {
            const messageHandler = message => {
                assert.include(['2a669cd3-983d-44d0-9761-d60fd3ba8fa5', 'fe1b2e28-9200-48b2-b2ff-5a82be53c359'], message.MessageId);
            };
            const res = await sqsClient.receiveMessages(messageHandler);
            assert.deepEqual(res, [dummyResponseDeleteMessage, dummyResponseDeleteMessage]);
        });
    }
);
9
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
5