2020-02-18 14:59:28 +13:00

216 lines
7.3 KiB
JavaScript

'use strict';
const _ = require('lodash');
const { expect } = require('chai');
const log = require('log').get('serverless:test');
const awsRequest = require('@serverless/test/aws-request');
const fixtures = require('../../fixtures');
const { getTmpDirPath } = require('../../utils/fs');
const {
createTestService,
deployService,
removeService,
fetch,
} = require('../../utils/integration');
describe('HTTP API Integration Test', function() {
this.timeout(1000 * 60 * 20); // Involves time-taking deploys
let serviceName;
let endpoint;
let stackName;
let tmpDirPath;
const stage = 'dev';
const resolveEndpoint = async () => {
const result = await awsRequest('CloudFormation', 'describeStacks', { StackName: stackName });
const endpointOutput = _.find(result.Stacks[0].Outputs, { OutputKey: 'HttpApiUrl' })
.OutputValue;
endpoint = endpointOutput.match(/https:\/\/.+\.execute-api\..+\.amazonaws\.com/)[0];
};
describe('Specific endpoints', () => {
let poolId;
let clientId;
const userName = 'test-http-api';
const userPassword = 'razDwa3!';
before(async () => {
tmpDirPath = getTmpDirPath();
log.debug('temporary path %s', tmpDirPath);
poolId = (
await awsRequest('CognitoIdentityServiceProvider', 'createUserPool', {
PoolName: `test-http-api-${process.hrtime()[1]}`,
})
).UserPool.Id;
[clientId] = await Promise.all([
awsRequest('CognitoIdentityServiceProvider', 'createUserPoolClient', {
ClientName: 'test-http-api',
UserPoolId: poolId,
ExplicitAuthFlows: ['ALLOW_USER_PASSWORD_AUTH', 'ALLOW_REFRESH_TOKEN_AUTH'],
PreventUserExistenceErrors: 'ENABLED',
}).then(result => result.UserPoolClient.ClientId),
awsRequest('CognitoIdentityServiceProvider', 'adminCreateUser', {
UserPoolId: poolId,
Username: userName,
}).then(() =>
awsRequest('CognitoIdentityServiceProvider', 'adminSetUserPassword', {
UserPoolId: poolId,
Username: userName,
Password: userPassword,
Permanent: true,
})
),
]);
const serverlessConfig = await createTestService(tmpDirPath, {
templateDir: await fixtures.extend('httpApi', {
provider: {
httpApi: {
cors: { exposedResponseHeaders: 'X-foo' },
authorizers: {
someAuthorizer: {
identitySource: '$request.header.Authorization',
issuerUrl: `https://cognito-idp.us-east-1.amazonaws.com/${poolId}`,
audience: clientId,
},
},
},
},
functions: {
foo: {
events: [
{
httpApi: {
authorizer: 'someAuthorizer',
},
},
],
},
},
}),
});
serviceName = serverlessConfig.service;
stackName = `${serviceName}-${stage}`;
log.notice('deploying %s service', serviceName);
await deployService(tmpDirPath);
return resolveEndpoint();
});
after(async () => {
await awsRequest('CognitoIdentityServiceProvider', 'deleteUserPool', { UserPoolId: poolId });
if (!serviceName) return;
log.notice('Removing service...');
await removeService(tmpDirPath);
});
it('should expose an accessible POST HTTP endpoint', async () => {
const testEndpoint = `${endpoint}/some-post`;
const response = await fetch(testEndpoint, { method: 'POST' });
const json = await response.json();
expect(json).to.deep.equal({ method: 'POST', path: '/some-post' });
});
it('should expose an accessible paramed GET HTTP endpoint', async () => {
const testEndpoint = `${endpoint}/bar/whatever`;
const response = await fetch(testEndpoint, { method: 'GET' });
const json = await response.json();
expect(json).to.deep.equal({ method: 'GET', path: '/bar/whatever' });
});
it('should return 404 on not supported method', async () => {
const testEndpoint = `${endpoint}/foo`;
const response = await fetch(testEndpoint, { method: 'POST' });
expect(response.status).to.equal(404);
});
it('should return 404 on not configured path', async () => {
const testEndpoint = `${endpoint}/not-configured`;
const response = await fetch(testEndpoint, { method: 'GET' });
expect(response.status).to.equal(404);
});
it('should support CORS when indicated', async () => {
const testEndpoint = `${endpoint}/bar/whatever`;
const response = await fetch(testEndpoint, {
method: 'GET',
headers: { Origin: 'https://serverless.com' },
});
expect(response.headers.get('access-control-allow-origin')).to.equal('*');
expect(response.headers.get('access-control-expose-headers')).to.equal('x-foo');
});
it('should expose a GET HTTP endpoint backed by JWT authorization', async () => {
const testEndpoint = `${endpoint}/foo`;
const responseUnauthorized = await fetch(testEndpoint, {
method: 'GET',
});
expect(responseUnauthorized.status).to.equal(401);
const token = (
await awsRequest('CognitoIdentityServiceProvider', 'initiateAuth', {
AuthFlow: 'USER_PASSWORD_AUTH',
AuthParameters: { USERNAME: userName, PASSWORD: userPassword },
ClientId: clientId,
})
).AuthenticationResult.IdToken;
const responseAuthorized = await fetch(testEndpoint, {
method: 'GET',
headers: { Authorization: token },
});
const json = await responseAuthorized.json();
expect(json).to.deep.equal({ method: 'GET', path: '/foo' });
});
});
describe('Catch-all endpoints', () => {
before(async () => {
tmpDirPath = getTmpDirPath();
log.debug('temporary path %s', tmpDirPath);
const serverlessConfig = await createTestService(tmpDirPath, {
templateDir: fixtures.map.httpApiCatchAll,
});
serviceName = serverlessConfig.service;
stackName = `${serviceName}-${stage}`;
log.notice('deploying %s service', serviceName);
await deployService(tmpDirPath);
return resolveEndpoint();
});
after(async () => {
log.notice('Removing service...');
await removeService(tmpDirPath);
});
it('should catch all root endpoint', async () => {
const testEndpoint = `${endpoint}`;
const response = await fetch(testEndpoint, { method: 'GET' });
const json = await response.json();
expect(json).to.deep.equal({ method: 'GET', path: '/' });
});
it('should catch all whatever endpoint', async () => {
const testEndpoint = `${endpoint}/whatever`;
const response = await fetch(testEndpoint, { method: 'PATCH' });
const json = await response.json();
expect(json).to.deep.equal({ method: 'PATCH', path: '/whatever' });
});
it('should catch all methods on method catch all endpoint', async () => {
const testEndpoint = `${endpoint}/foo`;
const response = await fetch(testEndpoint, { method: 'PATCH' });
const json = await response.json();
expect(json).to.deep.equal({ method: 'PATCH', path: '/foo' });
});
});
});