[AWS Labs探訪] ServerlessなUI自動テストを実行する
AWSのサービスを利用して、サーバーレスにUI自動テストを実行してみます。 AWS Labs探訪とは GitHubには、[awslabs]というAWSが公開しているOrganizationsがあります。ここにはAWSサー […]
目次
AWSのサービスを利用して、サーバーレスにUI自動テストを実行してみます。
AWS Labs探訪とは
GitHubには、[awslabs]というAWSが公開しているOrganizationsがあります。ここにはAWSサービスを利用したサンプルコードや新しいSDK、オフィシャルイベントで開催されたワークショップのサンプルコードといった様々なコードが公開されています。有名所では、SAMなどもこのOrganizationsにホストされています。
ここにはそのまま使えるものからprodで使うなと書かれたものまで玉石混交です。AWS Labs探訪は、ここにDiveしてみて仕事に使えそうなものがないか探してみようという企画です。
今回紹介するプロジェクト
Serverless-Automated-UI-Testing
CodePipelineやCodeBuildを用いてUI自動テストをサーバーレスに実行するプロジェクトです。
プロジェクトをセットアップする
まずはGitからダウンロードします。
$ git clone https://github.com/awslabs/serverless-automated-ui-testing.git
$ cd serverless-automated-ui-testing
CodeCommitリポジトリの作成
続いてCodeCommitのリポジトリを作成します。
$ aws codecommit create-repository --repository-name automated-ui-testing --repository-description "Repository for Automated UI Testing and Continuous Delivery using CodePipeline."
{
"repositoryMetadata": {
"repositoryName": "automated-ui-testing",
"cloneUrlSsh": "ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/automated-ui-testing",
"lastModifiedDate": 1557796573.16,
"repositoryDescription": "Repository for Automated UI Testing and Continuous Delivery using CodePipeline.",
"cloneUrlHttp": "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/automated-ui-testing",
"creationDate": 1557796573.16,
"repositoryId": "xxxxxxxxxxxxxxx",
"Arn": "arn:aws:codecommit:us-east-1:372284591230:automated-ui-testing",
"accountId": "xxxxxxxx"
}
}
CloudFormationスタックの作製
automated-ui-testing-params.json
にSNSトピックやS3バケットの設定が記載されています。これを自分のアカウントの値に変更しておきましょう。
[
{
"ParameterKey": "SourceRepo",
"ParameterValue": "automated-ui-testing"
},
{
"ParameterKey": "ApprovalTopic",
"ParameterValue": "prod-approval-topic"
},
{
"ParameterKey": "ProductionBucket",
"ParameterValue": "production-s3-website-bucket"
}
]
設定ができたら、CloudFormationでデプロイします。
$ aws cloudformation create-stack \
--stack-name automateduitesting \
--template-body file://automated-ui-testing.yaml \
--parameters file://automated-ui-testing-params.json \
--capabilities CAPABILITY_NAMED_IAM
{
"StackId": "arn:aws:cloudformation:us-east-1:9999999999:stack/automateduitesting/b5ddf160-75e6-11e9-bd46-0eee31812ac2"
}
作成に成功したら、以下のような形でCLIからデータが見れます。
$ aws cloudformation describe-stacks --stack-name automateduitesting
{
"Stacks": [
{
"StackId": "arn:aws:cloudformation:us-east-1:372284591230:stack/automateduitesting/723b5980-75ea-11e9-bd46-0eee31812ac2",
"DriftInformation": {
"StackDriftStatus": "NOT_CHECKED"
},
"Description": "Template which creates automated UI testing using Selenium with AWS CodeBuild and AWS CodePipeline.\n",
"Parameters": [
{
"ParameterValue": "automated-ui-testing",
"ParameterKey": "SourceRepo"
},
{
"ParameterValue": "prod-approval-topic",
"ParameterKey": "ApprovalTopic"
},
{
"ParameterValue": "example.com",
"ParameterKey": "ProductionBucket"
}
],
"Tags": [],
"Outputs": [
{
"Description": "URL of Status Website",
"OutputKey": "StatusWebsite",
"OutputValue": "https://status-website-automateduitesting.s3-website-us-east-1.amazonaws.com"
},
{
"Description": "URL of Test Website",
"OutputKey": "TestWebsite",
"OutputValue": "https://test-website-automateduitesting.s3-website-us-east-1.amazonaws.com"
}
],
"EnableTerminationProtection": false,
"CreationTime": "2019-05-14T01:49:01.163Z",
"Capabilities": [
"CAPABILITY_NAMED_IAM"
],
"StackName": "automateduitesting",
"NotificationARNs": [],
"StackStatus": "CREATE_COMPLETE",
"DisableRollback": false,
"RollbackConfiguration": {}
}
]
}
–stack-nameに注意
このスタックは、stack-nameの値を使ってS3 BucketとCognito Identify Poolを作成します。そのため、両リソースの命名制約に引っかかってしまうとスタック作成に失敗します。
よくあるのは、汎用的なスタック名を利用して
のようなエラーを吐くパターンと、-(ハイフン)を利用してCognito Identity Poolのバリデーションに引っかかるパターンがあります。
test-output-automated-ui-testing already exists
テストを実行する
デプロイが終われば、あとはリリースパイプラインを走らせるだけです。
GitのリポジトリをローカルにcloneしてCodeCommitにアップするか、CodePipelineの設定を変えて、Forkした自分のリポジトリにつないでやればよいでしょう。
これでソースがアップデートされた際に、ビルドパイプラインが実行され、Firefox / Chrome / PhantomJSでのUIテストが走り出します。
PhantomJS?2年前のサンプルコードだから仕方ないです。気になるという人は、CloudFormationからCodeBuildの該当リソースを消してやりましょう。
テスト結果はブラウザから確認可能
UITest時、StatusページのデプロイがLambda経由で実行されます。
そのため、CloudFormationのURL of Status Website
というOutputにあるURLへアクセスすると、CodeBuildでのテスト結果を確認することができます。
ちなみにこのテーブルは、Cognito Identity Provider + DynamoDBでかなり力技で作られています。
/*jshint esversion: 6 */
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'Cognito_IDP_ID',
});
AWS.config.region = "AWS_REGION";
var ddb = new AWS.DynamoDB.DocumentClient();
var body, chrome_tab, firefox_tab;
var firstload = 1;
function getdata(modlist, params, brw){
var flag;
var tbl = document.createElement('table');
if (brw == 'Chrome'){
tbl.setAttribute('id', 'Chrome_table');
}
if (brw == 'Firefox'){
tbl.setAttribute('id', 'Firefox_table');
}
if (brw == 'PhantomJS'){
tbl.setAttribute('id', 'PhantomJS_table');
}
thead = tbl.createTHead();
tr = thead.insertRow();
td = tr.insertCell();
td.appendChild(document.createTextNode(brw));
td.style.fontSize = 'x-large';
td.style.fontWeight = 'bolder';
td.setAttribute('colSpan', '7');
tr = thead.insertRow();
tr.style.fontSize = 'large';
tr.style.fontWeight = 'bolder';
td = tr.insertCell();
td.appendChild(document.createTextNode('Module'));
td = tr.insertCell();
td.appendChild(document.createTextNode('Testcase'));
td = tr.insertCell();
td.appendChild(document.createTextNode('Status'));
td = tr.insertCell();
td.appendChild(document.createTextNode('Start Time'));
td = tr.insertCell();
td.appendChild(document.createTextNode('End Time'));
td = tr.insertCell();
td.appendChild(document.createTextNode('Time Taken (ms)'));
td = tr.insertCell();
td.appendChild(document.createTextNode('Error Message'));
ddb.scan(params, function (err, data) {
if (err) console.error(err, err.stack); // an error occurred
else {
tdata = data.Items;
console.log(tdata);
for (var mod in modlist){
var newmod = 1;
for (var tc in modlist[mod]){
if (newmod == 1){
tr = tbl.insertRow();
td = tr.insertCell();
td.appendChild(document.createTextNode(mod));
td.setAttribute('rowSpan', modlist[mod].length+1);
newmod = 0;
}
flag = 1;
for (i=0; i< tdata.length; i++){
tcdetails = tdata[i].testcaseid.split('-');
if (tdata[i].module == mod && tcdetails[0] == brw.toLowerCase() && tcdetails[1] == modlist[mod][tc]){
tr = tbl.insertRow();
td = tr.insertCell();
td.appendChild(document.createTextNode(modlist[mod][tc]));
td = tr.insertCell();
td.appendChild(document.createTextNode(tdata[i].details.Status));
if ( tdata[i].details.Status == 'Passed' ){
td.style.color = 'green';
}
else {
td.style.color = 'red';
}
td = tr.insertCell();
td.appendChild(document.createTextNode(tdata[i].details.StartTime));
td = tr.insertCell();
td.appendChild(document.createTextNode(tdata[i].details.EndTime));
td = tr.insertCell();
td.appendChild(document.createTextNode(tdata[i].details.TimeTaken));
td = tr.insertCell();
td.appendChild(document.createTextNode(tdata[i].details.ErrorMessage));
flag = 0;
}
}
if (flag == 1){
tr = tbl.insertRow();
td = tr.insertCell();
td.appendChild(document.createTextNode(modlist[mod][tc]));
td = tr.insertCell();
td.appendChild(document.createTextNode(' '));
td = tr.insertCell();
td.appendChild(document.createTextNode(' '));
td = tr.insertCell();
td.appendChild(document.createTextNode(' '));
td = tr.insertCell();
td.appendChild(document.createTextNode(' '));
td = tr.insertCell();
td.appendChild(document.createTextNode(' '));
}
}
}
}
});
return tbl;
}
function tableCreate() {
var modparams = {
TableName: 'Modules_Table',
};
var modlist = {};
console.log(modparams);
ddb.scan(modparams, function (err, data) {
if (err) console.error(err, err.stack);
else {
var mdata = data.Items;
for (var m in mdata){
modlist[mdata[m].module] = mdata[m].testcases;
}
}
});
var browsers = ['Chrome', 'Firefox', 'PhantomJS'];
var br;
var tbl;
var params;
for (br in browsers){
params = {
TableName: 'Status_Table',
FilterExpression: "begins_with(testcaseid, :tcid)",
ExpressionAttributeValues: {
":tcid": browsers[br].toLowerCase()
}
};
if (browsers[br] == 'Chrome'){
ch_tbl = getdata(modlist, params, 'Chrome');
}
if (browsers[br] == 'Firefox'){
ff_tbl = getdata(modlist, params, 'Firefox');
}
if (browsers[br] == 'PhantomJS'){
pjs_tbl = getdata(modlist, params, 'PhantomJS');
}
}
body.replaceChild(ff_tbl, document.getElementById('Firefox_table'));
body.replaceChild(ch_tbl, document.getElementById('Chrome_table'));
body.replaceChild(pjs_tbl, document.getElementById('PhantomJS_table'));
}
document.addEventListener("DOMContentLoaded", function(event) {
body = document.body;
if (firstload == 1){
chrome_tab = document.createElement('table');
firefox_tab = document.createElement('table');
phantomjs_tab = document.createElement('table');
chrome_tab.setAttribute('id', 'Chrome_table');
firefox_tab.setAttribute('id', 'Firefox_table');
phantomjs_tab.setAttribute('id', 'PhantomJS_table');
body.appendChild(chrome_tab);
body.appendChild(document.createElement('br'));
body.appendChild(firefox_tab);
body.appendChild(document.createElement('br'));
body.appendChild(phantomjs_tab);
tableCreate();
firstload = 0;
}
});
データソースはDynamoDBにあります。
テストケースはどこでみる?
tests/testsuite.py
がテストで実行されている様子です。
#!/usr/bin/env python
from __future__ import print_function
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from datetime import datetime
from botocore.exceptions import ClientError
import requests
import traceback
import os
import boto3
import inspect
import sys
import random
br = os.environ['BROWSER']
main_url = os.environ['WebURL']
module_table = os.environ['ModuleTable']
status_table = os.environ['StatusTable']
s3_output_bucket = os.environ['ArtifactBucket']
ddb = boto3.client('dynamodb')
s3 = boto3.client('s3')
s3_path_prefix = os.environ['CODEBUILD_BUILD_ID'].replace(':', '/')
def funcname():
return inspect.stack()[1][3]
def update_status(mod, tc, st, et, ss, er):
if et != ' ':
t_t = str(int(round((datetime.strptime(et, '%d-%m-%Y %H:%M:%S,%f') -
datetime.strptime(st, '%d-%m-%Y %H:%M:%S,%f')).microseconds, -3) / 1000))
else:
t_t = ' '
try:
if er:
ddb.update_item(Key={'module': {'S': mod}, 'testcaseid': {'S': br + '-' + tc}},
UpdateExpression="set details.StartTime = :st, details.EndTime = :e, details.#S = :s," +
"details.ErrorMessage = :er, details.TimeTaken = :tt",
ExpressionAttributeValues={':e': {'S': et}, ':s': {'S': ss}, ':st': {'S': st},
':er': {'S': er}, ':tt': {'S': t_t}},
TableName=status_table, ExpressionAttributeNames={'#S': 'Status'})
else:
ddb.update_item(Key={'module': {'S': mod}, 'testcaseid': {'S': br + '-' + tc}},
UpdateExpression="set details.StartTime = :st, details.EndTime = :e, details.#S = :s," +
"details.TimeTaken = :tt",
ExpressionAttributeValues={':e': {'S': et}, ':s': {'S': ss}, ':st': {'S': st},
':tt': {'S': t_t}},
TableName=status_table, ExpressionAttributeNames={'#S': 'Status'})
except ClientError as e:
if e.response['Error']['Code'] == 'ValidationException':
ddb.update_item(Key={'module': {'S': mod}, 'testcaseid': {'S': br + '-' + tc}},
UpdateExpression="set #atName = :atValue", ExpressionAttributeValues={
':atValue': {'M': {'StartTime': {'S': st}, 'EndTime': {'S': et}, 'Status': {'S': ss},
'ErrorMessage': {'S': er}, 'TimeTaken': {'S': t_t}}}},
TableName=status_table,
ExpressionAttributeNames={'#atName': 'details'})
else:
traceback.print_exc()
except:
traceback.print_exc()
def tc001(browser, mod, tc):
# Testcase to validate whether home page is displayed properly
fname = mod + '-' + tc + '.png'
starttime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
endtime = ' '
try:
update_status(mod, tc, starttime, endtime, 'Started', ' ')
browser.get(main_url)
assert 'AWS CodeBuild automation' in browser.title
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'kp')))
browser.get_screenshot_as_file(fname)
with open(fname, 'rb') as data:
s3.upload_fileobj(data, s3_output_bucket, s3_path_prefix + '/' + fname)
os.remove(fname)
print('Completed test %s' % funcname())
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Passed', ' ')
except:
print('Failed while running test %s' % funcname())
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', traceback.print_exc())
return -1
def tc002(browser, mod, tc):
# Testcase to validate whether button click is displayed properly
fname = mod + '-' + tc + '.png'
starttime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
endtime = ' '
todisplay = 'AWS CodeBuild is a fully managed build service that compiles source code,' + \
' runs tests, and produces software packages that are ready to deploy.'
try:
update_status(mod, tc, starttime, endtime, 'Started', ' ')
browser.get(main_url)
assert 'AWS CodeBuild automation' in browser.title
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'kp')))
browser.find_element_by_xpath("//*[@id='bc']/a").click()
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'displaybtn')))
assert 'AWS CodeBuild automation - Button Click.' in browser.title
browser.find_element_by_id('displaybtn').click()
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'cbbutton')))
displayed = browser.find_element_by_id('cbbutton').text
browser.get_screenshot_as_file(fname)
with open(fname, 'rb') as data:
s3.upload_fileobj(data, s3_output_bucket, s3_path_prefix + '/' + fname)
os.remove(fname)
print('Completed test %s' % funcname())
if todisplay == displayed:
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Passed', ' ')
else:
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', 'Didn\'t find the expected text to be displayed.')
return -1
except:
print('Failed while running test %s' % funcname())
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', traceback.print_exc())
return -1
def tc003(browser, mod, tc):
# Testcase to validate whether reset button is working properly
fname = mod + '-' + tc + '.png'
starttime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
endtime = ' '
try:
update_status(mod, tc, starttime, endtime, 'Started', ' ')
browser.get(main_url)
assert 'AWS CodeBuild automation' in browser.title
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'kp')))
browser.find_element_by_xpath("//*[@id='bc']/a").click()
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'displaybtn')))
assert 'AWS CodeBuild automation - Button Click.' in browser.title
browser.find_element_by_id('displaybtn').click()
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'cbbutton')))
displayed = browser.find_element_by_id('cbbutton').text
browser.find_element_by_id('resetbtn').click()
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'cbbutton')))
displayed = browser.find_element_by_id('cbbutton').text
browser.get_screenshot_as_file(fname)
with open(fname, 'rb') as data:
s3.upload_fileobj(data, s3_output_bucket, s3_path_prefix + '/' + fname)
os.remove(fname)
print('Completed test %s' % funcname())
if displayed:
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', 'Text was not reset as expected.')
return -1
else:
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Passed', ' ')
except:
print('Failed while running test %s' % funcname())
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', traceback.print_exc())
return -1
def tc004(browser, mod, tc):
# Testcase to validate whether check box is working properly
fname = mod + '-' + tc + '.png'
starttime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
endtime = ' '
try:
update_status(mod, tc, starttime, endtime, 'Started', ' ')
browser.get(main_url)
assert 'AWS CodeBuild automation' in browser.title
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'kp')))
browser.find_element_by_xpath("//*[@id='cb']/a").click()
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'box3')))
assert 'AWS CodeBuild automation - Check Box.' in browser.title
browser.find_element_by_id('box1').click()
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'cbbox1')))
displayed = browser.find_element_by_id('cbbox1').text
if displayed != 'Checkbox 1 checked.':
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', 'Checkbox1 text was not displayed.')
return -1
browser.find_element_by_id('box2').click()
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'cbbox2')))
displayed = browser.find_element_by_id('cbbox2').text
if displayed != 'Checkbox 2 checked.':
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', 'Checkbox2 text was not displayed.')
return -1
browser.find_element_by_id('box1').click()
WebDriverWait(browser, 20).until_not(EC.visibility_of_element_located((By.ID, 'cbbox1')))
displayed = browser.find_element_by_id('cbbox1').text
if displayed:
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', 'Checkbox1 text was displayed after unchecking.')
return -1
browser.get_screenshot_as_file(fname)
with open(fname, 'rb') as data:
s3.upload_fileobj(data, s3_output_bucket, s3_path_prefix + '/' + fname)
os.remove(fname)
print('Completed test %s' % funcname())
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Passed', ' ')
except:
print('Failed while running test %s' % funcname())
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', traceback.print_exc())
return -1
def tc005(browser, mod, tc):
# Testcase to validate whether dropdown is working properly
fname = mod + '-' + tc + '.png'
starttime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
endtime = ' '
try:
update_status(mod, tc, starttime, endtime, 'Started', ' ')
browser.get(main_url)
assert 'AWS CodeBuild automation' in browser.title
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'kp')))
browser.find_element_by_xpath("//*[@id='dd']/a").click()
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.NAME, 'cbdropdown')))
assert 'AWS CodeBuild automation - Dropdown.' in browser.title
browser.find_element_by_id('CP').click()
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'dvidrop')))
displayed = browser.find_element_by_id('dvidrop').text
cp_text = 'AWS CodePipeline is a continuous integration and continuous delivery service ' + \
'for fast and reliable application and infrastructure updates.'
if displayed != cp_text:
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', 'Expected text for CodePipeline' +
'from dropdown was not displayed.')
return -1
browser.find_element_by_id('CC').click()
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'dvidrop')))
displayed = browser.find_element_by_id('dvidrop').text
cc_text = 'AWS CodeCommit is a fully-managed source control service that makes it easy for ' + \
'companies to host secure and highly scalable private Git repositories.'
if displayed != cc_text:
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', 'Expected text for CodeCommit' +
'from dropdown was not displayed.')
return -1
browser.find_element_by_id('CB').click()
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'dvidrop')))
displayed = browser.find_element_by_id('dvidrop').text
cb_text = 'AWS CodeBuild is a fully managed build service that compiles source code, ' + \
'runs tests, and produces software packages that are ready to deploy.'
if displayed != cb_text:
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', 'Expected text for CodeBuild' +
'from dropdown was not displayed.')
return -1
browser.find_element_by_id('CD').click()
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'dvidrop')))
displayed = browser.find_element_by_id('dvidrop').text
cd_text = 'AWS CodeDeploy is a service that automates code deployments to any instance, ' + \
'including Amazon EC2 instances and instances running on-premises.'
if displayed != cd_text:
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', 'Expected text for CodeDeploy' +
'from dropdown was not displayed.')
return -1
browser.find_element_by_id('CS').click()
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'dvidrop')))
displayed = browser.find_element_by_id('dvidrop').text
cs_text = 'AWS CodeStar enables you to quickly develop, build, and deploy applications on AWS. ' + \
'AWS CodeStar provides a unified user interface, enabling you to easily manage your ' + \
'software development activities in one place.'
if displayed != cs_text:
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', 'Expected text for CodeStar' +
'from dropdown was not displayed.')
return -1
browser.find_element_by_id('emp').click()
# WebDriverWait(browser, 120).until(EC.visibility_of_element_located((By.ID, 'dvidrop')))
displayed = browser.find_element_by_id('dvidrop').text
if displayed:
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', 'Expected no text')
return -1
browser.get_screenshot_as_file(fname)
with open(fname, 'rb') as data:
s3.upload_fileobj(data, s3_output_bucket, s3_path_prefix + '/' + fname)
os.remove(fname)
print('Completed test %s' % funcname())
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Passed', ' ')
except:
print('Failed while running test %s' % funcname())
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', traceback.print_exc())
return -1
def tc006(browser, mod, tc):
# Testcase to validate whether images page is working properly
fname = mod + '-' + tc + '.png'
starttime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
endtime = ' '
try:
update_status(mod, tc, starttime, endtime, 'Started', ' ')
browser.get(main_url)
assert 'AWS CodeBuild automation' in browser.title
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'kp')))
browser.find_element_by_xpath("//*[@id='img']/a").click()
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'image1')))
assert 'AWS CodeBuild automation - Images.' in browser.title
image_list = browser.find_elements_by_tag_name('img')
for image in image_list:
imageurl = image.get_attribute('src')
imgfile = imageurl.split('/')[-1]
img_res = requests.head(imageurl)
if img_res.status_code != 200 and (img_res.status_code == 403 and imgfile != 'test3.png'):
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', 'Expected images not displayed.')
return -1
browser.get_screenshot_as_file(fname)
with open(fname, 'rb') as data:
s3.upload_fileobj(data, s3_output_bucket, s3_path_prefix + '/' + fname)
os.remove(fname)
print('Completed test %s' % funcname())
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Passed', ' ')
except:
print('Failed while running test %s' % funcname())
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', traceback.print_exc())
return -1
def tc007(browser, mod, tc):
# Testcase to validate whether keypress page is working properly
key_pos = [Keys.ALT, Keys.CONTROL, Keys.DOWN, Keys.ESCAPE, Keys.F1, Keys.F10, Keys.F11, Keys.F12, Keys.F2,
Keys.F3, Keys.F4, Keys.F5, Keys.F6, Keys.F7, Keys.F8, Keys.F9, Keys.LEFT, Keys.SHIFT, Keys.SPACE,
Keys.TAB, Keys.UP]
key_word = ['ALT', 'CONTROL', 'DOWN', 'ESCAPE', 'F1', 'F10', 'F11', 'F12', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7',
'F8', 'F9', 'LEFT', 'SHIFT', 'SPACE', 'TAB', 'UP']
fname = mod + '-' + tc + '.png'
starttime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
endtime = ' '
if br == 'firefox':
print('Skipping this test for FireFox due to gecko driver issue.')
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Skipped', 'Skipping this test for FireFox due' +
'to gecko driver issue.')
return 0
try:
update_status(mod, tc, starttime, endtime, 'Started', ' ')
browser.get(main_url)
assert 'AWS CodeBuild automation' in browser.title
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'kp')))
browser.find_element_by_xpath("//*[@id='kp']/a").click()
WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.ID, 'titletext')))
assert 'AWS CodeBuild automation - Key Press.' in browser.title
actions = webdriver.ActionChains(browser)
actions.move_to_element(browser.find_element_by_id('titletext'))
actions.click()
rnum = random.randrange(0, 20)
actions.send_keys(key_pos[rnum])
actions.perform()
WebDriverWait(browser, 5).until(EC.visibility_of_element_located((By.ID, 'keytext')))
displayed = browser.find_element_by_id('keytext').text
browser.get_screenshot_as_file(fname)
with open(fname, 'rb') as data:
s3.upload_fileobj(data, s3_output_bucket, s3_path_prefix + '/' + fname)
os.remove(fname)
if displayed != 'You pressed \'' + key_word[rnum] + '\' key.':
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', 'Expected key press not displayed.')
return -1
print('Completed test %s' % funcname())
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Passed', ' ')
except:
print('Failed while running test %s' % funcname())
endtime = datetime.strftime(datetime.today(), '%d-%m-%Y %H:%M:%S,%f')
update_status(mod, tc, starttime, endtime, 'Failed', traceback.print_exc())
return -1
def test_phantomjs():
phantomjs_function = os.environ['PhantomJSFunction']
mods = os.environ['MODULES'].split(',')
client = boto3.client('lambda')
for mod in mods:
mod_tcs = ddb.get_item(TableName=module_table, Key={'module': {'S': mod.strip()}})['Item']['testcases']['L']
for tc in mod_tcs:
tcname = str(tc['S'].strip())
try:
response = client.invoke(ClientContext=tcname, FunctionName=phantomjs_function, InvocationType='Event',
Payload="{\"testcase\": \"" + tcname + "\", \"module\": \"" +
mod.strip() + "\"}")
print(response)
except:
print('Failed while invoking test %s' % tcname)
traceback.print_exc()
print(traceback.print_exc())
if __name__ == '__main__':
if br.lower() == 'chrome':
browser = webdriver.Chrome()
elif br.lower() == 'firefox':
browser = webdriver.Firefox()
elif br.lower() == 'phantomjs':
test_phantomjs()
sys.exit(0)
else:
print('Unexpected browser value: %s', br)
sys.exit(-1)
mods = os.environ['MODULES'].split(',')
allmthd = globals().copy()
allmthd.update(locals())
for mod in mods:
mod_tcs = ddb.get_item(TableName=module_table, Key={'module': {'S': mod.strip()}})['Item']['testcases']['L']
for tc in mod_tcs:
tcname = str(tc['S'].strip())
method = allmthd.get(tcname)
if not method:
raise Exception("Test case %s is not implemented" % tc['S'].strip())
method(browser, mod.strip(), tcname)
if browser:
browser.quit()
終わりに
2年前と少し古いものでしたので、今ならもうちょっと実装が変わるのではという気はします。
ですが、例えばCloudWatch EventからLambdaを定期実行して、結果をDynamoDBに保存し、ステータスページに出す。という使い方や、Cucumber系のBDDツールで、featureをS3やDynamoDBから取得する形でテストケースを動的に変更できるようにするやりかたなども考えられるかなと思います。
Node.js使いとしては、puppeteerを使ってlighthouseなども実行するという方法も考えてみたいなと思いました。