DEV Community

Jaira Encio for AWS Community ASEAN

Posted on • Edited on

Creating an API that runs Selenium via AWS Lambda

Being an automation tester, my job is to automate everything. As I was running my test script via terminal I realised that I’m the only who can execute the scripts I made. What if someone wants to run it? like the Devs, Project Manager, etc. It would be a tedious task to clone my repo, install libraries, and run the script. So I decided that maybe I can store my test script inside a serverless machine and make it accessible via API request.

I experimented with various AWS resources such as creating my own lambda function, checking features of API gateway, Codepipeline, etc. After several attempts, I was finally able to run my script inside. And then I just researched how to access my lambda via API.

This will result in higher production and time savings. Engineers may focus on vital work because automated testing does not require human interaction. This is like a portable testing device that anyone could execute. With fast test execution, developers get testing reports in an instant, so whenever a failure occurs, they will react to it quickly.Β Test automation will make it easier to update programs quickly. As a result, automated testing leads to increased team responsiveness, improved user experience, and increased customer satisfaction.

Overview

  1. Create 2 Lambda layers that has selenium and chromedriver libraries
  2. Include created lambda layers in serverless.yml of lambda then deploy

Creating Selenium Lambda Layer

Place libraries in python/lib/python3.6/site-packages/ to include them in a layer.

DownloadΒ Selenium to layer directory



$Β pip3.6 install -t selenium/python/lib/python3.6/site-packages selenium==3.8.0
$Β cdΒ selenium
$Β zip -r python.zip python/


Enter fullscreen mode Exit fullscreen mode

OnceΒ finished, Create lambda layer then upload zip file

1.Β Go to AWS Console Lambda/Layers
2.Β Click Create Layer
3.Β Input the following in the layer configuration



Name:Β selenium
Description:Β Selenium layer
UploadΒ zip file created: python.zip
CompatibleΒ runtimes: Python 3.6


Enter fullscreen mode Exit fullscreen mode

selenium-layer

4.Β Click Create

Note: You can user whatever version you prefer, you just need to select compatible runtime when uploading your package

Β Creating Chromedriver Lambda layer

DownloadΒ chrome driver



$Β mkdir -p chromedriver
$Β cdΒ chromedriver
$Β curl -SL https://chromedriver.storage.googleapis.com/2.37/chromedriver_linux64.zipΒ >Β chromedriver.zip
$Β unzip chromedriver.zip
$Β rm chromedriver.zip


Enter fullscreen mode Exit fullscreen mode

DownloadΒ chrome binary



$Β curl -SL https://github.com/adieuadieu/serverless-chrome/releases/download/v1.0.0-41/stable-headless-chromium-amazonlinux-2017-03.zipΒ >Β headless-chromium.zip
$Β unzip headless-chromium.zip
$Β rm headless-chromium.zip


Enter fullscreen mode Exit fullscreen mode

CompressΒ driver and binary



$Β ls
chromedriverΒ headless-chromium
$Β zip -r chromedriver.zip chromedriver headless-chromium


Enter fullscreen mode Exit fullscreen mode

OnceΒ finished, Create lambda layer then upload zip file

1.Β Go to AWS Console Lambda/Layers
2.Β Click Create Layer
3.Β Input the following in the layer configuration



Name:Β chromedriver
Description:Β chrome driver and binary layer
UploadΒ zip file created: chromedriver.zip
CompatibleΒ runtimes: Python 3.6


Enter fullscreen mode Exit fullscreen mode

chrome-layer

4.Β Click Create

Β Creating Lambda Function

To ensure that your function code has access to libraries included in layers, Lambda runtimes include paths in the '/opt' directory.

Β File Structure


 shell
── /lambda/ Β  Β  Β  Β  Β  Β #Β lambda function
Β  β”œβ”€β”€ /handler.py Β  Β  Β #Β source code of lambda function 
Β  └── /serverless.yaml #Β serverless config


Enter fullscreen mode Exit fullscreen mode

Β Code

CopyΒ the code below to /lambda/handler.py



fromΒ selenium import webdriver
fromΒ selenium.webdriver.chrome.options import Options

def main(event, context):
    options = Options()
    options.binary_location = '/opt/headless-chromium'
    options.add_argument('--headless')
    options.add_argument('--no-sandbox')
    options.add_argument('--single-process')
    options.add_argument('--disable-dev-shm-usage')

    driver = webdriver.Chrome('/opt/chromedriver',chrome_options=options)
    driver.get('https://www.google.com/')

    driver.close();
    driver.quit();

    response = {
        "statusCode": 200,
        "body": "Selenium Headless Chrome Initialized"
    }

    return response


Enter fullscreen mode Exit fullscreen mode

CopyΒ the code below to /lambda/serverless.yaml.



service: selenium-lambda

provider:
  name: aws
  runtime: python3.6
  region: ap-southeast-2
  timeout: 900

functions:
  main:
    memorySize: 1000
    handler: handler.main
    events:
      - http:
          path: test
          method: get

    layers:
      - arn:aws:lambda:ap-southeast-2:{}:layer:chromedriver:2
      - arn:aws:lambda:ap-southeast-2:{}:layer:selenium:2

resources:
  Resources:
    ApiGatewayRestApi:
      Properties:
        BinaryMediaTypes:
          - "*/*"


Enter fullscreen mode Exit fullscreen mode

Β Deploy Lambda Function

GoΒ to /lambdaΒ directory



$Β sls deploy


Enter fullscreen mode Exit fullscreen mode

Β Output



Serverless:Β Stack update finished...
ServiceΒ Information
service:Β selenium-lambda
stage:Β dev
region:Β ap-southeast-2
stack:Β selenium-lambda-dev
apiΒ keys:
Β  None
endpoints:
Β  GET - https://{name}.execute-api.ap-southeast-2.amazonaws.com/dev/test
functions:
Β  main: selenium-lambda-dev-main


Enter fullscreen mode Exit fullscreen mode

output

YouΒ should get same response as below when accessing API



{
"statusCode":Β 200,
"body":Β "Selenium HeadlessΒ Chrome Initialized"
}


Enter fullscreen mode Exit fullscreen mode

This deployment automatically creates cloudformation stack and s3 bucket.

Cloudformation stack

S3

Deprecation note:

Since python3.6 has been deprecated, you can try using the ff packages compatible with 3.9. note that if this exceeds lambda function zip file, you can try using docker image or uploading to s3 instead.



$ python3.9 -m pip install -t python/lib/python3.9/site-packages selenium==4.5.0
$ cd selenium
$ zip -r python.zip python/


Enter fullscreen mode Exit fullscreen mode

Name: selenium
Description: Selenium layer
Upload zip file created: python.zip
Compatible runtimes: Python 3.9



$ mkdir -p chromedriver
$ cd chromedriver
$ curl -SL https://chromedriver.storage.googleapis.com/107.0.5304.62/chromedriver_linux64.zip > chromedriver.zip
$ unzip chromedriver.zip
$ rm chromedriver.zip


Enter fullscreen mode Exit fullscreen mode


$ curl -SL https://github.com/adieuadieu/serverless-chrome/releases/download/v1.0.0-57/stable-headless-chromium-amazonlinux-2.zip > headless-chromium.zip
$ unzip headless-chromium.zip
$ rm headless-chromium.zip


Enter fullscreen mode Exit fullscreen mode

References for new releases:
chromedriver release
https://chromedriver.chromium.org/downloads

serverless-chrome release
https://github.com/adieuadieu/serverless-chrome/releases

Checkout Achim's comment on how he used 3.9 using dockerimage
https://dev.to/achimgrolimund/comment/22d99

Jaira Encio Linkedin

Oldest comments (48)

Collapse
 
quibski profile image
quibski AWS Community ASEAN

Surely many Devs and QA will benefit from this. Hopefully a demo can be made/shown

Collapse
 
tchua profile image
tchua

+1 to this, a demo would be great!

Collapse
 
jairaencio profile image
Jaira Encio AWS Community ASEAN

uhm hahaha

Collapse
 
chrisjeriel profile image
chrisjeriel

Great work! A well-thought-out article, straightforward and concise. Looking forward more advanced implementations.

Collapse
 
lunchcodes profile image
LunchCodes

Exactly what I needed! Thank you!

Collapse
 
raphael_jambalos profile image
Raphael Jambalos AWS Community ASEAN

The article is very helpful! It brings automation to the next level. By having running automated tests in a more automated way, developers will be empowered to make sure their code runs optimally.

Collapse
 
jlgarcia profile image
jltuts

Good job jai! Very helpful!

Collapse
 
chiggy_wiggy profile image
Maynard Prepotente • Edited

Great Job! Will definitely help a lot of Devs and QA! Adding screenshots of the output will make the job easier tho =)

Collapse
 
rolinj profile image
rolinj

Kudos Jai! Great tutorial indeed!
For reference, may you add as well some screenshots of the created cloudformation stack and s3 bucket on the output section? Thanks :D

Collapse
 
jairaencio profile image
Jaira Encio AWS Community ASEAN

Uploaded screenshots of cloudformation and s3 bucket. Thanks for the feedback :)

Collapse
 
ivy07 profile image
Ivy β˜•

Great help! Will definitely need more articles like this un the future.

Collapse
 
ranzeyxc profile image
ranzey

Huge help! :)

Collapse
 
silencer017 profile image
silencer017

Well done, this is very informative!