diff --git a/node/package-lock.json b/node/package-lock.json index c4782886..4904035a 100644 --- a/node/package-lock.json +++ b/node/package-lock.json @@ -1,6 +1,6 @@ { "name": "dc-api-build", - "version": "2.4.0", + "version": "2.4.1", "lockfileVersion": 3, "requires": true, "packages": { @@ -14,6 +14,7 @@ }, "devDependencies": { "@openapitools/openapi-generator-cli": "^2.5.2", + "aws-sdk-client-mock": "^4.0.1", "chai": "^4.2.0", "chai-http": "^4.3.0", "choma": "^1.2.1", @@ -4134,6 +4135,21 @@ "@types/send": "*" } }, + "node_modules/@types/sinon": { + "version": "10.0.20", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.20.tgz", + "integrity": "sha512-2APKKruFNCAZgx3daAyACGzWuJ028VVCUDk6o2rw/Z4PXT0ogwdV4KUegW0MwVs0Zu59auPXbbuBJHF12Sx1Eg==", + "dev": true, + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", + "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", + "dev": true + }, "node_modules/@types/superagent": { "version": "4.1.13", "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.13.tgz", @@ -4336,6 +4352,17 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, + "node_modules/aws-sdk-client-mock": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/aws-sdk-client-mock/-/aws-sdk-client-mock-4.0.1.tgz", + "integrity": "sha512-yD2mmgy73Xce097G5hIpr1k7j50qzvJ49/+6osGZiCyk4m6cwhb+2x7kKFY1gEMwTzaS8+m8fXv9SB29SkRYyQ==", + "dev": true, + "dependencies": { + "@types/sinon": "^10.0.10", + "sinon": "^16.1.3", + "tslib": "^2.1.0" + } + }, "node_modules/axios": { "version": "1.6.8", "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", @@ -8653,12 +8680,8 @@ } }, "src": { -<<<<<<< HEAD "name": "dc-api", "version": "2.4.1", -======= - "version": "2.4.0", ->>>>>>> 452c4d8 (Validate request body) "license": "Apache-2.0", "devDependencies": { "@aws-crypto/sha256-browser": "^2.0.1", diff --git a/node/package.json b/node/package.json index c706817c..e425e555 100644 --- a/node/package.json +++ b/node/package.json @@ -19,6 +19,7 @@ }, "devDependencies": { "@openapitools/openapi-generator-cli": "^2.5.2", + "aws-sdk-client-mock": "^4.0.1", "chai": "^4.2.0", "chai-http": "^4.3.0", "choma": "^1.2.1", diff --git a/node/src/package-lock.json b/node/src/package-lock.json index fe69c6bb..d5511670 100644 --- a/node/src/package-lock.json +++ b/node/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "dc-api", - "version": "2.4.0", + "version": "2.4.1", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/node/test/integration/post-chat-feedback.test.js b/node/test/integration/post-chat-feedback.test.js index 960171b4..06873c2c 100644 --- a/node/test/integration/post-chat-feedback.test.js +++ b/node/test/integration/post-chat-feedback.test.js @@ -2,104 +2,118 @@ const chai = require("chai"); const expect = chai.expect; chai.use(require("chai-http")); const ApiToken = requireSource("api/api-token"); +const { mockClient } = require("aws-sdk-client-mock"); +const { S3Client, PutObjectCommand } = require("@aws-sdk/client-s3"); const { handler } = requireSource("handlers/post-chat-feedback"); describe("Chat feedback route", () => { + const s3Mock = mockClient(S3Client); helpers.saveEnvironment(); beforeEach(() => { - process.env.API_TOKEN_SECRET = "abc123"; - process.env.API_TOKEN_NAME = "dcapiTEST"; - process.env.MEDIACONVERT_DESTINATION_BUCKET = "delete-me"; + s3Mock.reset(); }); - it("should return 401 if user is not logged in", async () => { - let requestBody = JSON.stringify({ - sentiment: "positive", - context: { - ref: "5a6e1d76-0d4c-43c5-ab2c-4687112ba102", - question: "What is the capital of France?", - answer: "Paris", - source_documents: ["https://doc1", "https://doc2"], - }, - feedback: { - options: ["option1"], - text: "Great answer!", - email: "user@example.com", - }, + describe("Form POST submission", () => { + beforeEach(() => { + s3Mock.on(PutObjectCommand).resolves({}); }); - const event = helpers - .mockEvent("POST", "/chat-feedback") - .body(requestBody) - .render(); - const response = await handler(event); - expect(response.statusCode).to.equal(401); - expect(response.body).to.equal("Authorization Required"); - }); - - it("should fail if request body is invalid", async () => { - const token = new ApiToken().user({ uid: "abc123" }).sign(); + it("should return 401 if user is not logged in", async () => { + let requestBody = JSON.stringify({ + sentiment: "positive", + context: { + ref: "5a6e1d76-0d4c-43c5-ab2c-4687112ba102", + question: "What is the capital of France?", + answer: "Paris", + source_documents: ["https://doc1", "https://doc2"], + }, + feedback: { + options: ["option1"], + text: "Great answer!", + email: "user@example.com", + }, + }); - let requestBody = JSON.stringify({ - sentiment: "neutral", - context: { - ref: "3fc98004-995b-4491-94fd-aea48a0363ba", - question: "What is the capital of France?", - answer: "Paris", - source_documents: ["https://doc1", "https://doc2"], - }, - feedback: { - options: ["option1"], - text: "Great answer!", - email: "user@example.com", - }, + const event = helpers + .mockEvent("POST", "/chat-feedback") + .body(requestBody) + .render(); + const response = await handler(event); + expect(response.statusCode).to.equal(401); + expect(response.body).to.equal("Authorization Required"); }); - const event = helpers - .mockEvent("POST", "/chat-feedback") - .body(requestBody) - .headers({ - Cookie: `${process.env.API_TOKEN_NAME}=${token}`, - }) - .render(); - const response = await handler(event); - expect(response.statusCode).to.equal(400); - expect(response.body).to.equal( - `"sentiment is not one of enum values: positive,negative"` - ); - }); + it("should fail if request body is invalid", async () => { + const token = new ApiToken().user({ uid: "abc123" }).sign(); - // it("should upload to S3 and return 200 on valid input", async () => { - // const token = new ApiToken().user({ uid: "abc123" }).sign(); + let requestBody = JSON.stringify({ + sentiment: "neutral", + context: { + ref: "3fc98004-995b-4491-94fd-aea48a0363ba", + question: "What is the capital of France?", + answer: "Paris", + source_documents: ["https://doc1", "https://doc2"], + }, + feedback: { + options: ["option1"], + text: "Great answer!", + email: "user@example.com", + }, + }); - // const requestBody = JSON.stringify({ - // sentiment: "negative", - // context: { - // ref: "e6005d7c-e03b-43f7-94a3-e327b4b5a538", - // question: "What is the capital of France?", - // answer: "Rome", - // source_documents: ["https://doc1", "https://doc2"], - // }, - // feedback: { - // options: ["option1"], - // text: "Bad answer!", - // email: "example@example.com" - // } - // }); + const event = helpers + .mockEvent("POST", "/chat-feedback") + .body(requestBody) + .headers({ + Cookie: `${process.env.API_TOKEN_NAME}=${token}`, + }) + .render(); + const response = await handler(event); + expect(response.statusCode).to.equal(400); + expect(response.body).to.equal( + `"sentiment is not one of enum values: positive,negative"` + ); + }); - // nock(`https://${process.env.MEDIACONVERT_DESTINATION_BUCKET}.s3.amazonaws.com`).put('/1001').reply(200); + describe("Saving feedback", () => { + xit("should upload to S3 and return 200", async () => { + const token = new ApiToken().user({ uid: "abc123" }).sign(); - // const event = helpers - // .mockEvent("POST", "/chat-feedback") - // .body(requestBody) - // .headers({ - // Cookie: `${process.env.API_TOKEN_NAME}=${token}`, - // }) - // .render(); - // const response = await handler(event); - // expect(response.statusCode).to.equal(200); - // expect(response.body).to.equal('{"message":"Feedback received. Thank you."}'); - // }); + const requestBody = JSON.stringify({ + sentiment: "negative", + context: { + ref: "e6005d7c-e03b-43f7-94a3-e327b4b5a538", + question: "What is the capital of France?", + answer: "Rome", + source_documents: ["https://doc1", "https://doc2"], + }, + feedback: { + options: ["option1"], + text: "Bad answer!", + email: "example@example.com", + }, + }); + + const event = helpers + .mockEvent("POST", "/chat-feedback") + .body(requestBody) + .headers({ + Cookie: `${process.env.API_TOKEN_NAME}=${token}`, + }) + .render(); + const response = await handler(event); + expect(response.statusCode).to.equal(200); + expect(response.body).to.equal( + '{"message":"Feedback received. Thank you."}' + ); + expect(s3Mock.calls(PutObjectCommand).length).to.equal(1); + expect(s3Mock.calls(0).args[0].input).lessThanOrEqual({ + Bucket: process.env.MEDIACONVERT_DESTINATION_BUCKET, + Key: "negative/e6005d7c-e03b-43f7-94a3-e327b4b5a538", + }); + }); + }); + }); }); diff --git a/node/test/test-helpers/index.js b/node/test/test-helpers/index.js index 84e4afa3..097dff30 100644 --- a/node/test/test-helpers/index.js +++ b/node/test/test-helpers/index.js @@ -14,6 +14,7 @@ const TestEnvironment = { NUSSO_BASE_URL: "https://nusso-base.com/", NUSSO_API_KEY: "abc123", WEBSOCKET_URI: "wss://thisisafakewebsocketapiurl", + MEDIA_CONVERT_DESTINATION_BUCKET: "test-mediaconvert-destination-bucket", }; for (const v in TestEnvironment) delete process.env[v];