748 lines
22 KiB
TypeScript
748 lines
22 KiB
TypeScript
import fse from 'fs-extra';
|
|
import path from 'path';
|
|
|
|
import { mockDomain } from 'aws-domain';
|
|
import { mockS3 } from '@serverless/aws-s3';
|
|
import { mockUpload } from 'aws-sdk';
|
|
import { mockLambda, mockLambdaPublish } from 'aws-lambda';
|
|
import { mockCloudFront } from 'aws-cloudfront';
|
|
|
|
import NextjsComponent, { DEFAULT_LAMBDA_CODE_DIR, API_LAMBDA_CODE_DIR } from '../src/component';
|
|
import { getDomains } from '../src/utils';
|
|
import { cleanupFixtureDirectory } from './test-utils';
|
|
|
|
const createNextComponent = (inputs) => {
|
|
const component = new NextjsComponent(inputs);
|
|
component.context.credentials = {
|
|
aws: {
|
|
accessKeyId: '123',
|
|
secretAccessKey: '456',
|
|
},
|
|
};
|
|
return component;
|
|
};
|
|
|
|
const mockServerlessComponentDependencies = ({ expectedDomain }) => {
|
|
mockS3.mockResolvedValue({
|
|
name: 'bucket-xyz',
|
|
});
|
|
|
|
mockLambda.mockResolvedValue({
|
|
arn: 'arn:aws:lambda:us-east-1:123456789012:function:my-func',
|
|
});
|
|
|
|
mockLambdaPublish.mockResolvedValue({
|
|
version: 'v1',
|
|
});
|
|
|
|
mockCloudFront.mockResolvedValueOnce({
|
|
url: 'https://cloudfrontdistrib.amazonaws.com',
|
|
});
|
|
|
|
mockDomain.mockResolvedValueOnce({
|
|
domains: [expectedDomain],
|
|
});
|
|
};
|
|
|
|
describe('Custom inputs', () => {
|
|
let componentOutputs;
|
|
let consoleWarnSpy;
|
|
|
|
beforeEach(() => {
|
|
const realFseRemove = fse.remove.bind({});
|
|
jest.spyOn(fse, 'remove').mockImplementation((filePath) => {
|
|
// don't delete mocked .next/ files as they're needed for the tests and committed to source control
|
|
if (!filePath.includes('.next' + path.sep)) {
|
|
return realFseRemove(filePath);
|
|
}
|
|
});
|
|
|
|
consoleWarnSpy = jest.spyOn(console, 'warn').mockReturnValue();
|
|
});
|
|
|
|
afterEach(() => {
|
|
fse.remove.mockRestore();
|
|
consoleWarnSpy.mockRestore();
|
|
});
|
|
|
|
describe.each`
|
|
inputRegion | expectedRegion
|
|
${undefined} | ${'us-east-1'}
|
|
${'eu-west-2'} | ${'eu-west-2'}
|
|
`(`When input region is $inputRegion`, ({ inputRegion, expectedRegion }) => {
|
|
const fixturePath = path.join(__dirname, './fixtures/generic-fixture');
|
|
let tmpCwd;
|
|
|
|
beforeEach(async () => {
|
|
tmpCwd = process.cwd();
|
|
process.chdir(fixturePath);
|
|
|
|
mockServerlessComponentDependencies({});
|
|
|
|
const component = createNextComponent({});
|
|
|
|
componentOutputs = await component({
|
|
bucketRegion: inputRegion,
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.chdir(tmpCwd);
|
|
return cleanupFixtureDirectory(fixturePath);
|
|
});
|
|
|
|
it(`passes the ${expectedRegion} region to s3 component`, () => {
|
|
expect(mockS3).toBeCalledWith(
|
|
expect.objectContaining({
|
|
region: expectedRegion,
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe.each`
|
|
inputDomains | expectedDomain
|
|
${['dev', 'example.com']} | ${'https://dev.example.com'}
|
|
${['www', 'example.com']} | ${'https://www.example.com'}
|
|
${'example.com'} | ${'https://www.example.com'}
|
|
${[undefined, 'example.com']} | ${'https://www.example.com'}
|
|
${'example.com'} | ${'https://www.example.com'}
|
|
`('Custom domain', ({ inputDomains, expectedDomain }) => {
|
|
const fixturePath = path.join(__dirname, './fixtures/generic-fixture');
|
|
let tmpCwd;
|
|
|
|
beforeEach(async () => {
|
|
tmpCwd = process.cwd();
|
|
process.chdir(fixturePath);
|
|
|
|
mockServerlessComponentDependencies({
|
|
expectedDomain,
|
|
});
|
|
|
|
const component = createNextComponent({});
|
|
|
|
componentOutputs = await component({
|
|
policy: 'arn:aws:iam::aws:policy/CustomRole',
|
|
domain: inputDomains,
|
|
description: 'Custom description',
|
|
memory: 512,
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.chdir(tmpCwd);
|
|
return cleanupFixtureDirectory(fixturePath);
|
|
});
|
|
|
|
it('uses domain to provision custom domain', () => {
|
|
const { domain, subdomain } = getDomains(inputDomains);
|
|
|
|
expect(mockDomain).toBeCalledWith({
|
|
defaultCloudfrontInputs: {},
|
|
domainType: 'both',
|
|
privateZone: false,
|
|
domain,
|
|
subdomains: {
|
|
[subdomain as string]: {
|
|
url: 'https://cloudfrontdistrib.amazonaws.com',
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
it('uses custom policy document provided', () => {
|
|
expect(mockLambda).toBeCalledWith(
|
|
expect.objectContaining({
|
|
description: expect.stringContaining('Custom description'),
|
|
role: expect.objectContaining({
|
|
policy: {
|
|
arn: 'arn:aws:iam::aws:policy/CustomRole',
|
|
},
|
|
}),
|
|
})
|
|
);
|
|
});
|
|
|
|
it('outputs custom domain url', () => {
|
|
expect(componentOutputs.appUrl).toEqual(expectedDomain);
|
|
});
|
|
});
|
|
|
|
describe.each`
|
|
nextConfigDir | nextStaticDir | fixturePath
|
|
${'nextConfigDir'} | ${'nextStaticDir'} | ${path.join(__dirname, './fixtures/split-app')}
|
|
`('nextConfigDir=$nextConfigDir, nextStaticDir=$nextStaticDir', ({ fixturePath, ...inputs }) => {
|
|
let tmpCwd;
|
|
|
|
beforeEach(async () => {
|
|
tmpCwd = process.cwd();
|
|
process.chdir(fixturePath);
|
|
|
|
mockServerlessComponentDependencies({});
|
|
|
|
const component = createNextComponent({});
|
|
|
|
componentOutputs = await component({
|
|
nextConfigDir: inputs.nextConfigDir,
|
|
nextStaticDir: inputs.nextStaticDir,
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.chdir(tmpCwd);
|
|
return cleanupFixtureDirectory(fixturePath);
|
|
});
|
|
|
|
it('uploads static assets to S3 correctly', () => {
|
|
expect(mockUpload).toBeCalledWith(
|
|
expect.objectContaining({
|
|
Key: expect.stringMatching('_next/static/test-build-id/placeholder.js'),
|
|
})
|
|
);
|
|
expect(mockUpload).toBeCalledWith(
|
|
expect.objectContaining({
|
|
Key: expect.stringMatching('static-pages/terms.html'),
|
|
})
|
|
);
|
|
expect(mockUpload).toBeCalledWith(
|
|
expect.objectContaining({
|
|
Key: expect.stringMatching('static/donotdelete.txt'),
|
|
})
|
|
);
|
|
expect(mockUpload).toBeCalledWith(
|
|
expect.objectContaining({
|
|
Key: expect.stringMatching('public/favicon.ico'),
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe.each`
|
|
publicDirectoryCache | expected
|
|
${undefined} | ${'public, max-age=31536000, must-revalidate'}
|
|
${false} | ${undefined}
|
|
${{ test: '/.(ico|png)$/i', value: 'public, max-age=306000' }} | ${'public, max-age=306000'}
|
|
`(
|
|
'input=inputPublicDirectoryCache, expected=$expectedPublicDirectoryCache',
|
|
({ publicDirectoryCache, expected }) => {
|
|
let tmpCwd;
|
|
const fixturePath = path.join(__dirname, './fixtures/simple-app');
|
|
|
|
beforeEach(async () => {
|
|
tmpCwd = process.cwd();
|
|
process.chdir(fixturePath);
|
|
|
|
mockServerlessComponentDependencies({});
|
|
|
|
const component = createNextComponent({});
|
|
|
|
componentOutputs = await component({
|
|
publicDirectoryCache,
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.chdir(tmpCwd);
|
|
return cleanupFixtureDirectory(fixturePath);
|
|
});
|
|
|
|
it(`sets the ${expected} Cache - Control header on ${publicDirectoryCache} `, () => {
|
|
expect(mockUpload).toBeCalledWith(
|
|
expect.objectContaining({
|
|
Key: expect.stringMatching('public/favicon.ico'),
|
|
CacheControl: expected,
|
|
})
|
|
);
|
|
});
|
|
}
|
|
);
|
|
|
|
describe.each([
|
|
[undefined, { defaultMemory: 512, apiMemory: 512 }],
|
|
[{}, { defaultMemory: 512, apiMemory: 512 }],
|
|
[1024, { defaultMemory: 1024, apiMemory: 1024 }],
|
|
[{ defaultLambda: 1024 }, { defaultMemory: 1024, apiMemory: 512 }],
|
|
[{ apiLambda: 2048 }, { defaultMemory: 512, apiMemory: 2048 }],
|
|
[
|
|
{ defaultLambda: 128, apiLambda: 2048 },
|
|
{ defaultMemory: 128, apiMemory: 2048 },
|
|
],
|
|
])('Lambda memory input', (inputMemory, expectedMemory) => {
|
|
const fixturePath = path.join(__dirname, './fixtures/generic-fixture');
|
|
let tmpCwd;
|
|
|
|
beforeEach(async () => {
|
|
tmpCwd = process.cwd();
|
|
process.chdir(fixturePath);
|
|
|
|
mockServerlessComponentDependencies({});
|
|
|
|
const component = createNextComponent({
|
|
memory: inputMemory,
|
|
});
|
|
|
|
componentOutputs = await component({
|
|
memory: inputMemory,
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.chdir(tmpCwd);
|
|
return cleanupFixtureDirectory(fixturePath);
|
|
});
|
|
|
|
it(`sets default lambda memory to ${expectedMemory.defaultMemory} and api lambda memory to ${expectedMemory.apiMemory} `, () => {
|
|
const { defaultMemory, apiMemory } = expectedMemory;
|
|
|
|
// default Lambda
|
|
expect(mockLambda).toBeCalledWith(
|
|
expect.objectContaining({
|
|
code: path.join(fixturePath, DEFAULT_LAMBDA_CODE_DIR),
|
|
memory: defaultMemory,
|
|
})
|
|
);
|
|
|
|
// api Lambda
|
|
expect(mockLambda).toBeCalledWith(
|
|
expect.objectContaining({
|
|
code: path.join(fixturePath, API_LAMBDA_CODE_DIR),
|
|
memory: apiMemory,
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe.each`
|
|
inputTimeout | expectedTimeout
|
|
${undefined} | ${{ defaultTimeout: 10, apiTimeout: 10 }}
|
|
${{}} | ${{ defaultTimeout: 10, apiTimeout: 10 }}
|
|
${40} | ${{ defaultTimeout: 40, apiTimeout: 40 }}
|
|
${{ defaultLambda: 20 }} | ${{ defaultTimeout: 20, apiTimeout: 10 }}
|
|
${{ apiLambda: 20 }} | ${{ defaultTimeout: 10, apiTimeout: 20 }}
|
|
${{ defaultLambda: 15, apiLambda: 20 }} | ${{ defaultTimeout: 15, apiTimeout: 20 }}
|
|
`('Input timeout options', ({ inputTimeout, expectedTimeout }) => {
|
|
let tmpCwd;
|
|
const fixturePath = path.join(__dirname, './fixtures/generic-fixture');
|
|
|
|
beforeEach(async () => {
|
|
tmpCwd = process.cwd();
|
|
process.chdir(fixturePath);
|
|
|
|
mockServerlessComponentDependencies({});
|
|
|
|
const component = createNextComponent({});
|
|
|
|
componentOutputs = await component({
|
|
timeout: inputTimeout,
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.chdir(tmpCwd);
|
|
return cleanupFixtureDirectory(fixturePath);
|
|
});
|
|
|
|
it(`sets default lambda timeout to ${expectedTimeout.defaultTimeout} and api lambda timeout to ${expectedTimeout.apiTimeout} `, () => {
|
|
const { defaultTimeout, apiTimeout } = expectedTimeout;
|
|
|
|
expect(mockLambda).toBeCalledWith(
|
|
expect.objectContaining({
|
|
code: path.join(fixturePath, DEFAULT_LAMBDA_CODE_DIR),
|
|
timeout: defaultTimeout,
|
|
})
|
|
);
|
|
|
|
expect(mockLambda).toBeCalledWith(
|
|
expect.objectContaining({
|
|
code: path.join(fixturePath, API_LAMBDA_CODE_DIR),
|
|
timeout: apiTimeout,
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe.each`
|
|
inputRuntime | expectedRuntime
|
|
${undefined} | ${{ defaultRuntime: 'nodejs12.x', apiRuntime: 'nodejs12.x' }}
|
|
${{}} | ${{ defaultRuntime: 'nodejs12.x', apiRuntime: 'nodejs12.x' }}
|
|
${'nodejs10.x'} | ${{ defaultRuntime: 'nodejs10.x', apiRuntime: 'nodejs10.x' }}
|
|
${{ defaultLambda: 'nodejs10.x' }} | ${{ defaultRuntime: 'nodejs10.x', apiRuntime: 'nodejs12.x' }}
|
|
${{ apiLambda: 'nodejs10.x' }} | ${{ defaultRuntime: 'nodejs12.x', apiRuntime: 'nodejs10.x' }}
|
|
${{ defaultLambda: 'nodejs10.x', apiLambda: 'nodejs10.x' }} | ${{ defaultRuntime: 'nodejs10.x', apiRuntime: 'nodejs10.x' }}
|
|
`('Input runtime options', ({ inputRuntime, expectedRuntime }) => {
|
|
let tmpCwd;
|
|
const fixturePath = path.join(__dirname, './fixtures/generic-fixture');
|
|
|
|
beforeEach(async () => {
|
|
tmpCwd = process.cwd();
|
|
process.chdir(fixturePath);
|
|
|
|
mockServerlessComponentDependencies({});
|
|
|
|
const component = createNextComponent({});
|
|
|
|
componentOutputs = await component({
|
|
runtime: inputRuntime,
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.chdir(tmpCwd);
|
|
return cleanupFixtureDirectory(fixturePath);
|
|
});
|
|
|
|
it(`sets default lambda runtime to ${expectedRuntime.defaultRuntime} and api lambda runtime to ${expectedRuntime.apiRuntime} `, () => {
|
|
const { defaultRuntime, apiRuntime } = expectedRuntime;
|
|
|
|
expect(mockLambda).toBeCalledWith(
|
|
expect.objectContaining({
|
|
code: path.join(fixturePath, DEFAULT_LAMBDA_CODE_DIR),
|
|
runtime: defaultRuntime,
|
|
})
|
|
);
|
|
|
|
expect(mockLambda).toBeCalledWith(
|
|
expect.objectContaining({
|
|
code: path.join(fixturePath, API_LAMBDA_CODE_DIR),
|
|
runtime: apiRuntime,
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe.each`
|
|
inputName | expectedName
|
|
${undefined} | ${{ defaultName: undefined, apiName: undefined }}
|
|
${{}} | ${{ defaultName: undefined, apiName: undefined }}
|
|
${'fooFunction'} | ${{ defaultName: 'fooFunction', apiName: 'fooFunction' }}
|
|
${{ defaultLambda: 'fooFunction' }} | ${{ defaultName: 'fooFunction', apiName: undefined }}
|
|
${{ apiLambda: 'fooFunction' }} | ${{ defaultName: undefined, apiName: 'fooFunction' }}
|
|
${{ defaultLambda: 'fooFunction', apiLambda: 'barFunction' }} | ${{ defaultName: 'fooFunction', apiName: 'barFunction' }}
|
|
`('Lambda name input', ({ inputName, expectedName }) => {
|
|
let tmpCwd;
|
|
const fixturePath = path.join(__dirname, './fixtures/generic-fixture');
|
|
|
|
beforeEach(async () => {
|
|
tmpCwd = process.cwd();
|
|
process.chdir(fixturePath);
|
|
|
|
mockServerlessComponentDependencies({});
|
|
|
|
const component = createNextComponent({});
|
|
|
|
componentOutputs = await component({
|
|
name: inputName,
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.chdir(tmpCwd);
|
|
return cleanupFixtureDirectory(fixturePath);
|
|
});
|
|
|
|
it(`sets default lambda name to ${expectedName.defaultName} and api lambda name to ${expectedName.apiName} `, () => {
|
|
const { defaultName, apiName } = expectedName;
|
|
|
|
const expectedDefaultObject = {
|
|
code: path.join(fixturePath, DEFAULT_LAMBDA_CODE_DIR),
|
|
};
|
|
if (defaultName) expectedDefaultObject.name = defaultName;
|
|
|
|
expect(mockLambda).toBeCalledWith(expect.objectContaining(expectedDefaultObject));
|
|
|
|
const expectedApiObject = {
|
|
code: path.join(fixturePath, API_LAMBDA_CODE_DIR),
|
|
};
|
|
if (apiName) expectedApiObject.name = apiName;
|
|
|
|
expect(mockLambda).toBeCalledWith(expect.objectContaining(expectedApiObject));
|
|
});
|
|
});
|
|
|
|
describe.each([
|
|
// no input
|
|
[undefined, {}],
|
|
// empty input
|
|
[{}, {}],
|
|
// ignores origin-request and origin-response triggers as they're reserved by serverless-next.js
|
|
[
|
|
{
|
|
defaults: {
|
|
ttl: 500,
|
|
'lambda@edge': {
|
|
'origin-request': 'ignored',
|
|
'origin-response': 'also ignored',
|
|
},
|
|
},
|
|
},
|
|
{ defaults: { ttl: 500 } },
|
|
],
|
|
// allow lamdba@edge triggers other than origin-request and origin-response
|
|
[
|
|
{
|
|
defaults: {
|
|
ttl: 500,
|
|
'lambda@edge': {
|
|
'viewer-request': 'used value',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
defaults: {
|
|
ttl: 500,
|
|
'lambda@edge': { 'viewer-request': 'used value' },
|
|
},
|
|
},
|
|
],
|
|
[
|
|
{
|
|
defaults: {
|
|
forward: { cookies: 'all', headers: 'X', queryString: true },
|
|
},
|
|
},
|
|
{
|
|
defaults: {
|
|
forward: { cookies: 'all', headers: 'X', queryString: true },
|
|
},
|
|
},
|
|
],
|
|
// ignore custom lambda@edge origin-request trigger set on the api cache behaviour
|
|
[
|
|
{
|
|
'api/*': {
|
|
ttl: 500,
|
|
'lambda@edge': { 'origin-request': 'ignored value' },
|
|
},
|
|
},
|
|
{ 'api/*': { ttl: 500 } },
|
|
],
|
|
// allow other lambda@edge triggers on the api cache behaviour
|
|
[
|
|
{
|
|
'api/*': {
|
|
ttl: 500,
|
|
'lambda@edge': { 'origin-response': 'used value' },
|
|
},
|
|
},
|
|
{
|
|
'api/*': {
|
|
ttl: 500,
|
|
'lambda@edge': { 'origin-response': 'used value' },
|
|
},
|
|
},
|
|
],
|
|
// custom origins and expanding relative URLs to full S3 origin
|
|
[
|
|
{
|
|
origins: [
|
|
'http://some-origin',
|
|
'/relative',
|
|
{ url: 'http://diff-origin' },
|
|
{ url: '/diff-relative' },
|
|
],
|
|
},
|
|
{
|
|
origins: [
|
|
'http://some-origin',
|
|
'http://bucket-xyz.s3.amazonaws.com/relative',
|
|
{ url: 'http://diff-origin' },
|
|
{ url: 'http://bucket-xyz.s3.amazonaws.com/diff-relative' },
|
|
],
|
|
},
|
|
],
|
|
// custom page cache behaviours
|
|
[
|
|
{
|
|
'/terms': {
|
|
ttl: 5500,
|
|
'misc-param': 'misc-value',
|
|
'lambda@edge': {
|
|
'origin-request': 'ignored value',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
'/terms': {
|
|
ttl: 5500,
|
|
'misc-param': 'misc-value',
|
|
},
|
|
},
|
|
],
|
|
[
|
|
{
|
|
'/customers/stan-sack': {
|
|
ttl: 5500,
|
|
},
|
|
},
|
|
{
|
|
'/customers/stan-sack': {
|
|
ttl: 5500,
|
|
},
|
|
},
|
|
],
|
|
])('Custom cloudfront inputs', (inputCloudfrontConfig, expectedInConfig) => {
|
|
let tmpCwd;
|
|
const fixturePath = path.join(__dirname, './fixtures/generic-fixture');
|
|
const { origins = [], defaults = {}, ...other } = expectedInConfig;
|
|
|
|
const expectedDefaultCacheBehaviour = {
|
|
...defaults,
|
|
'lambda@edge': {
|
|
'origin-request': 'arn:aws:lambda:us-east-1:123456789012:function:my-func:v1',
|
|
...defaults['lambda@edge'],
|
|
},
|
|
};
|
|
|
|
const expectedApiCacheBehaviour = {
|
|
...expectedInConfig['api/*'],
|
|
allowedHttpMethods: ['HEAD', 'DELETE', 'POST', 'GET', 'OPTIONS', 'PUT', 'PATCH'],
|
|
'lambda@edge': {
|
|
...(expectedInConfig['api/*'] && expectedInConfig['api/*']['lambda@edge']),
|
|
'origin-request': 'arn:aws:lambda:us-east-1:123456789012:function:my-func:v1',
|
|
},
|
|
};
|
|
|
|
const customPageCacheBehaviours = {};
|
|
Object.entries(other).forEach(([path, cacheBehaviour]) => {
|
|
customPageCacheBehaviours[path] = {
|
|
...cacheBehaviour,
|
|
'lambda@edge': {
|
|
'origin-request': 'arn:aws:lambda:us-east-1:123456789012:function:my-func:v1',
|
|
...(cacheBehaviour && cacheBehaviour['lambda@edge']),
|
|
},
|
|
};
|
|
});
|
|
|
|
const cloudfrontConfig = {
|
|
defaults: {
|
|
ttl: 0,
|
|
allowedHttpMethods: ['HEAD', 'GET'],
|
|
forward: {
|
|
cookies: 'all',
|
|
queryString: true,
|
|
},
|
|
compress: true,
|
|
...expectedDefaultCacheBehaviour,
|
|
},
|
|
origins: [
|
|
{
|
|
pathPatterns: {
|
|
...customPageCacheBehaviours,
|
|
'_next/static/*': {
|
|
...customPageCacheBehaviours['_next/static/*'],
|
|
ttl: 86400,
|
|
forward: {
|
|
headers: 'none',
|
|
cookies: 'none',
|
|
queryString: false,
|
|
},
|
|
},
|
|
'_next/data/*': {
|
|
ttl: 0,
|
|
allowedHttpMethods: ['HEAD', 'GET'],
|
|
'lambda@edge': {
|
|
'origin-request': 'arn:aws:lambda:us-east-1:123456789012:function:my-func:v1',
|
|
},
|
|
},
|
|
'api/*': {
|
|
ttl: 0,
|
|
...expectedApiCacheBehaviour,
|
|
},
|
|
'static/*': {
|
|
...customPageCacheBehaviours['static/*'],
|
|
ttl: 86400,
|
|
forward: {
|
|
headers: 'none',
|
|
cookies: 'none',
|
|
queryString: false,
|
|
},
|
|
},
|
|
},
|
|
private: true,
|
|
url: 'http://bucket-xyz.s3.amazonaws.com',
|
|
},
|
|
...origins,
|
|
],
|
|
};
|
|
|
|
beforeEach(async () => {
|
|
tmpCwd = process.cwd();
|
|
process.chdir(fixturePath);
|
|
|
|
mockServerlessComponentDependencies({});
|
|
|
|
const component = createNextComponent({});
|
|
|
|
componentOutputs = await component({
|
|
cloudfront: inputCloudfrontConfig,
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.chdir(tmpCwd);
|
|
return cleanupFixtureDirectory(fixturePath);
|
|
});
|
|
|
|
it('Sets cloudfront options if present', () => {
|
|
expect(mockCloudFront).toBeCalledWith(expect.objectContaining(cloudfrontConfig));
|
|
});
|
|
});
|
|
|
|
describe.each`
|
|
cloudFrontInput | expectedErrorMessage
|
|
${{ 'some-invalid-page-route': { ttl: 100 } }} | ${'Could not find next.js pages for "some-invalid-page-route"'}
|
|
${{ '/api': { ttl: 100 } }} | ${'route "/api" is not supported'}
|
|
${{ api: { ttl: 100 } }} | ${'route "api" is not supported'}
|
|
${{ 'api/test': { ttl: 100 } }} | ${'route "api/test" is not supported'}
|
|
`('Invalid cloudfront inputs', ({ cloudFrontInput, expectedErrorMessage }) => {
|
|
const fixturePath = path.join(__dirname, './fixtures/generic-fixture');
|
|
let tmpCwd;
|
|
|
|
beforeEach(async () => {
|
|
tmpCwd = process.cwd();
|
|
process.chdir(fixturePath);
|
|
|
|
mockServerlessComponentDependencies({});
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.chdir(tmpCwd);
|
|
return cleanupFixtureDirectory(fixturePath);
|
|
});
|
|
|
|
it('throws the correct error', async () => {
|
|
expect.assertions(1);
|
|
|
|
try {
|
|
await createNextComponent({})({
|
|
cloudfront: cloudFrontInput,
|
|
});
|
|
} catch (err) {
|
|
expect(err.message).toContain(expectedErrorMessage);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('Build using serverless trace target', () => {
|
|
const fixturePath = path.join(__dirname, './fixtures/simple-app');
|
|
let tmpCwd;
|
|
|
|
beforeEach(async () => {
|
|
tmpCwd = process.cwd();
|
|
process.chdir(fixturePath);
|
|
|
|
mockServerlessComponentDependencies({});
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.chdir(tmpCwd);
|
|
return cleanupFixtureDirectory(fixturePath);
|
|
});
|
|
|
|
it('builds correctly', async () => {
|
|
await createNextComponent({})({
|
|
useServerlessTraceTarget: true,
|
|
});
|
|
});
|
|
});
|
|
});
|