When developing any dynamic functionality it is best practice to implement testing. This will ensure anytime the code
is deployed it is in a working state and will provide a good user experience to the visitors/users of your service.
Although it’s possible to write a custom test framework, it’s much easier to use an existing solution. This example
will use Jest. Start by installing Jest with NPM.
The next step is to create a test. As the example project only has one JavaScript function these instructions will only
implement a test for it. There is no reason many more tests can’t be created. To make it easy to find tests the new
test will be created in tests/functions/urlRewrite.test.js.
// Load the file to test const urlRewrite = require('../../functions/urlRewrite'); // Load some data that can be reused for other lambda@Edge functions const lambdaAtEdgeFixture = require('../fixtures/lambdaAtEdge');
test( 'url-rewrite handler does not append index.html to root-directory requests', () => { const expectedResponse = { uri: lambdaAtEdgeFixture.event.file.Records[0].cf.request.uri }; expect( urlRewrite.handler( lambdaAtEdgeFixture.event.file, lambdaAtEdgeFixture.context.webClient, lambdaAtEdgeFixture.callback ) ).toEqual(expect.objectContaining(expectedResponse)); } );
test( 'url-rewrite handler does not append index.html to non-directory requests', () => { const expectedResponse = { uri: lambdaAtEdgeFixture.event.file_in_subdirectory.Records[0].cf.request.uri }; expect( urlRewrite.handler( lambdaAtEdgeFixture.event.file_in_subdirectory, lambdaAtEdgeFixture.context.webClient, lambdaAtEdgeFixture.callback ) ).toEqual(expect.objectContaining(expectedResponse)); } );
The 4th line of the test includes a file that doesn’t exist yet. This file contains some sample values that can be
reused if we need to test other Lambda@Edge functions. Create the file at tests/fixtures/lambdaAtEdge.js (this is a
large file so the content is at the bottom of this post).
Now that the javascript is tested, it’s worth testing the links on the static site to make sure they are valid. For
this broken-link-checker-local can do all the hard work, so
install it.
1
npm i broken-link-checker-local --save-dev
As long as the site has been deployed previously (it has been if you’re following all the blog posts) it’s possible to
test for broken links.
Remembering the right commands, especially when managing multiple sites, can be confusing and easy to forget. To avoid
this, it’s possible to define some scripts in the pacakge.json file. The commands to add are as follows:
clean: a simple wrapper for hexo clean
build: a wrapper for hexo generate
buildclean: a wrapper for both clean and build
linkcheck: run the link checking script
jest: run the jest tests
test: run an end-to-end test
1 2 3 4 5 6 7 8
"scripts": { "clean": "hexo clean", "build": "hexo generate", "cleanbuild": "npm run clean && npm run build", "linkcheck": "blcl --filter-level 3 --get --recursive public", "jest": "jest", "test": "npm run cleanbuild && npm run jest && npm run linkcheck" }
// Load the file to test const urlRewriteTest = require('../../functions/urlRewrite'); // Load some data that can be reused for other lambda@Edge functions const lambdaAtEdgeFixture = require('../fixtures/lambdaAtEdge');
# Plugins for additional Serverless functionality plugins: -serverless-s3-deploy -serverless-plugin-scripts -'@silvermine/serverless-plugin-cloudfront-lambda-edge'
# Configuration for AWS provider: name:aws runtime:nodejs8.10 profile:serverless # Some future functionality requires us to use us-east-1 at this time region:us-east-1
# This enables us to use the default stage definition, but override it from the command line stage:${opt:stage,self:provider.stage} # This enables us to prepend the stage name for non-production environments domain: fulldomain: prod:${self:custom.domain.domain} other:${self:custom.stage}.${self:custom.domain.domain} # This value has been customised so I can maintain multiple demonstration sites domain:${self:custom.postname}.${self:custom.domain.zonename} domainname:${self:custom.domain.fulldomain.${self:custom.stage},self:custom.domain.fulldomain.other} # DNS Zone name (this is only required so I can maintain multiple demonstration sites) zonename:alphageek.com.au cacheControlMaxAgeHTMLByStage: # HTML Cache time for production environment prod:3600 # HTML Cache time for other environments other:0 cacheControlMaxAgeHTML:${self:custom.domain.cacheControlMaxAgeHTMLByStage.${self:custom.stage},self:custom.domain.cacheControlMaxAgeHTMLByStage.other} sslCertificateARN:arn:aws:acm:us-east-1:165657443288:certificate/61d202ea-12f2-4282-b602-9c3b83183c7a assets: targets: # Configuration for HTML files (overriding the default cache control age) -bucket: Ref:WebsiteS3Bucket acl:private files: -source:./public/ headers: CacheControl:max-age=${self:custom.domain.cacheControlMaxAgeHTML} empty:true globs: -'**/*.html' # Configuration for all assets -bucket: Ref:WebsiteS3Bucket acl:private files: -source:./public/ empty:true globs: -'**/*.js' -'**/*.css' -'**/*.jpg' -'**/*.png' -'**/*.gif' scripts: hooks: # Run these commands when creating the deployment artifacts package:createDeploymentArtifacts:> hexo clean && hexo generate # Run these commands after infrastructure changes have been completed deploy:finalize:> sls s3deploy -s ${self:custom.stage} # AWS Region to S3 website hostname mapping s3DNSName: us-east-2:s3-website.us-east-2.amazonaws.com us-east-1:s3-website-us-east-1.amazonaws.com us-west-1:s3-website-us-west-1.amazonaws.com us-west-2:s3-website-us-west-2.amazonaws.com ap-south-1:s3-website.ap-south-1.amazonaws.com ap-northeast-3:s3-website.ap-northeast-3.amazonaws.com ap-northeast-2:s3-website.ap-northeast-2.amazonaws.com ap-southeast-1:s3-website-ap-southeast-1.amazonaws.com ap-southeast-2:s3-website-ap-southeast-2.amazonaws.com ap-northeast-1:s3-website-ap-northeast-1.amazonaws.com ca-central-1:s3-website.ca-central-1.amazonaws.com eu-central-1:s3-website.eu-central-1.amazonaws.com eu-west-1:s3-website-eu-west-1.amazonaws.com eu-west-2:s3-website.eu-west-2.amazonaws.com eu-west-3:s3-website.eu-west-3.amazonaws.com eu-north-1:s3-website.eu-north-1.amazonaws.com sa-east-1:s3-website-sa-east-1.amazonaws.com # Determine what resources file to include based on the current stage customConfigFile:${self:custom.customConfigFiles.${self:custom.stage},self:custom.customConfigFiles.other} customConfigFiles: prod:prod other:other
# Define the Lambda functions for the site functions: # This function will be deployed to Lambda@Edge and rewrite URLs to include index.html urlrewrite: name:${self:service}-${self:custom.stage}-cf-url-rewriter handler:functions/urlRewrite.handler memorySize:128 timeout:1 lambdaAtEdge: distribution:WebsiteCloudFrontDistribution eventType:origin-request
# Define the resources we will need to host the site resources: # Include the resources file -${file(config/resources.yml)} # Include the outputs file -${file(config/outputs.yml)} # Include a custom configuration file based on the environment -${file(config/resources/environment/${self:custom.customConfigFile}.yml)}