serverless/test/integration/aws/function-url.test.js
2024-05-29 11:51:04 -04:00

142 lines
4.3 KiB
JavaScript

'use strict'
const { expect } = require('chai')
const awsRequest = require('@serverless/test/aws-request')
const CloudFormationService = require('aws-sdk').CloudFormation
const fixtures = require('../../fixtures/programmatic')
const aws4 = require('aws4')
const url = require('url')
const {
deployService,
removeService,
fetch,
} = require('../../utils/integration')
describe('test/integration/aws/function-url.test.js', function () {
this.timeout(1000 * 60 * 10) // Involves time-taking deploys
let stackName
let serviceDir
let basicEndpoint
let otherEndpoint
let authedEndpoint
let streamedEndpoint
const stage = 'dev'
before(async () => {
const serviceData = await fixtures.setup('function', {
configExt: {
functions: {
basic: {
url: true,
},
other: {
url: {
cors: {
exposedResponseHeaders: ['x-foo'],
allowCredentials: true,
allowedMethods: ['GET'],
},
},
},
authed: {
handler: 'basic.handler',
url: {
authorizer: 'aws_iam',
},
},
streamed: {
handler: 'stream.handler',
url: {
invokeMode: 'RESPONSE_STREAM',
},
},
},
},
})
;({ servicePath: serviceDir } = serviceData)
const serviceName = serviceData.serviceConfig.service
stackName = `${serviceName}-${stage}`
await deployService(serviceDir)
const describeStacksResponse = await awsRequest(
CloudFormationService,
'describeStacks',
{
StackName: stackName,
},
)
basicEndpoint = describeStacksResponse.Stacks[0].Outputs.find(
(output) => output.OutputKey === 'BasicLambdaFunctionUrl',
).OutputValue
otherEndpoint = describeStacksResponse.Stacks[0].Outputs.find(
(output) => output.OutputKey === 'OtherLambdaFunctionUrl',
).OutputValue
authedEndpoint = describeStacksResponse.Stacks[0].Outputs.find(
(output) => output.OutputKey === 'AuthedLambdaFunctionUrl',
).OutputValue
streamedEndpoint = describeStacksResponse.Stacks[0].Outputs.find(
(output) => output.OutputKey === 'StreamedLambdaFunctionUrl',
).OutputValue
})
after(async () => {
if (!serviceDir) return
await removeService(serviceDir)
})
it('should return valid response from Lambda URL', async () => {
const expectedMessage = 'Basic'
const response = await fetch(basicEndpoint, { method: 'GET' })
const jsonResponse = await response.json()
expect(jsonResponse.message).to.equal(expectedMessage)
})
it('should return valid response from Lambda URL with authorizer with valid signature', async () => {
const expectedMessage = 'Basic'
const signedParams = aws4.sign(
{
service: 'lambda',
region: 'us-east-1',
method: 'GET',
host: url.parse(authedEndpoint).hostname,
},
{
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
},
)
const response = await fetch(authedEndpoint, signedParams)
const jsonResponse = await response.json()
expect(jsonResponse.message).to.equal(expectedMessage)
})
it('should return invalid response from Lambda URL with authorizer without passed signature', async () => {
const expectedMessage = 'Forbidden'
const response = await fetch(authedEndpoint, { method: 'GET' })
const jsonResponse = await response.json()
expect(jsonResponse.Message).to.equal(expectedMessage)
})
it('should return expected CORS headers from Lambda URL', async () => {
const response = await fetch(otherEndpoint, {
method: 'GET',
headers: { Origin: 'https://serverless.com' },
})
const headers = response.headers
expect(headers.get('access-control-expose-headers')).to.equal('x-foo')
expect(headers.get('access-control-allow-credentials')).to.equal('true')
})
it('should return streaming invoke mode Lambda URL', async () => {
const expectedMessage = 'Hello'
let responseMessage = ''
const response = await fetch(streamedEndpoint, { method: 'GET' })
for await (const chunk of response.body) {
responseMessage += chunk.toString()
}
expect(responseMessage).to.equal(expectedMessage)
})
})