1652753826
Laravel Dusk provides an expressive, easy-to-use browser automation and testing API. By default, Dusk does not require you to install JDK or Selenium on your machine. Instead, Dusk uses a standalone Chromedriver. However, you are free to utilize any other Selenium driver you wish.
Documentation for Dusk can be found on the Laravel website.
Thank you for considering contributing to Dusk! The contribution guide can be found in the Laravel documentation.
In order to ensure that the Laravel community is welcoming to all, please review and abide by the Code of Conduct.
Please review our security policy on how to report security vulnerabilities.
Laravel Dusk is open-sourced software licensed under the MIT license.
As an open source PHP framework, Laravel was created to build applications while also prioritizing testing, aided by the out-of-the-box testing package called PHPUnit. However, while PHPUnit is one of the most popular and highly efficient packages for performing unit tests in PHP, PHPUnit cannot test JavaScript functionalities, driving the need for a JavaScript-specific testing package.
Normally, developers can use Selenium for JavaScript testing, but setting it up and learning to use it can be quite challenging. So, Laravel developers decided to provide an easier alternative: Dusk.
Dusk is a Laravel package that performs end-to-end (E2E) tests on Laravel applications. Providing client-side testing by running tests in a browser, Dusk allows developers to see client-side features tested in real time, mimicking how a user would use them.
Built on ChromeDriver and the PHP WebDriver, Dusk also provides browser automation for applications while eliminating the complex steps required by ChromeDriver and PHP WebDriver individually.
Tailored specifically for Laravel users, Dusk’s support of JavaScript and AJAX provides the JavaScript functionality the Symfony BrowserKit component can’t support, and it is easier to use than Selenium. And with Dusk, repeating tasks within applications can now be automated.
In this post, we will install Laravel Dusk in an application and run some browser tests with it to see how it works and the benefits it provides.
After building an application, and before shipping, developers must run various tests to ensure an app’s features are functioning as expected. But even after shipping, new features that are added to improve the application must also be tested.
By running E2E tests, developers can ensure newly added features don’t break the pre-existing ones by simulating users using the application.
To begin using Dusk, create a new Laravel project in your preferred directory:
laravel new project-name
Next, move into the directory of your new project:
cd project-name
You can add Dusk to it with Composer by running the following command:
composer require --dev laravel/dusk
Note that Dusk is a development tool and must never be added to your production environment.
Register the service provider in app\Providers\AppServiceProvider.php
using an if
statement that only makes it available for development:
use Laravel\Dusk\DuskServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
if ($this->app->environment('local', 'testing')) {
$this->app->register(DuskServiceProvider::class);
}
}
}
By importing DuskServiceProvider
and implementing it inside an if
statement, this ensures that DuskServiceProvider
is only available in your local environment for testing purposes.
Complete the Dusk installation in your project by running the following:
php artisan dusk:install
This creates a Browser
folder in your tests
directory. The ExampleTest.php
file inside the folder contains an example test that you can run or edit.
You must also specify the browser URL that Dusk can test your application with. Usually, http://localhost:8000
is used in local environments. Navigate to your .env
file and ensure that your APP_URL
key points to your specified URL.
If you don’t want to mess with your main database, you can create a replica of it for testing; simply create a file named .env.dusk.local
in your root directory.
Whenever you run a test, your main .env
file will be backed up, and .env.dusk.local
will be renamed .env
and used. After the test, this process reverses so you can access your main .env
file.
First, let’s check out the example test that came with the Dusk installation, ExampleTest.php
:
<?php
namespace Tests\Browser;
use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
class ExampleTest extends DuskTestCase
{
/**
* A basic browser test example.
*
* @return void
*/
public function testBasicExample()
{
$this->browse(function (Browser $browser) {
$browser->visit('/')
->assertSee('Laravel');
});
}
}
Run php artisan serve
in another command window. Your application must be running and accessible at localhost:8000
for Dusk to carry out tests on it.
To execute ExampleTest.php
, run the following command:
php artisan dusk
Here, the Browser
class imports and creates an instance of it.
The Browser
class contains many useful methods to carry out various actions in the web browser. For example, the visit
method opens the URL that it is provided within a browser. Since http://localhost:8000
is the default URL of your application, if nothing is passed as an argument to visit
, it opens this default URL.
Next, the assertSee
method checks if the text on a page is the same as the supplied reference text.
In ExampleTest.php
, visit
opens the homepage of your application, assertSee
checks to see whether the word “Laravel” appears on your homepage, and the browse
method calls the function that carries out these tasks.
Think of assertions as simple checks that you can run on your application to see what’s present in it and what’s absent. Check out the complete list of Laravel Dusk assertions here.
When the test is successful, your CLI shows a simple “OK” message.
Dusk also comes with a useful debugging feature. If you run a test and it fails, a picture of the failed test saves to the screenshots
folder. For example, try checking for a piece of text that’s not on your homepage:
public function testBasicExample()
{
$this->browse(function (Browser $browser) {
$browser->visit('/')
->assertSee('exampleText');
});
}
Here, you see whether the text supplied to assertSee
is somewhere on the page. Since it isn’t, the test fails and a screenshot of it is saved to the tests\Browser\screenshots
directory.
With your understanding of how a basic test works with Dusk, you can now test Laravel’s built-in authentication system.
Since you’ll need a database to save new user information, create one and add its details to your .env
file:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=testDB
DB_USERNAME=root
DB_PASSWORD=
Using Laravel Jetstream’s authentication scaffolding, add Jetstream to your application by running the following command:
composer require laravel/jetstream
Jetstream offers two frontend stack options to pick from: Inertia.js and Livewire. In this example, use Livewire because it’s based on Vue.js and provides registration, login, and dashboard features:
php artisan jetstream:install livewire
To complete your Livewire setup, run the following:
npm install && npm run dev
After creating some migration files that contain table designs for your authentication system, generate the required tables in your database by running the following:
php artisan migrate
Now, with the register, login, and dashboard features, run your application and check them out:
php artisan serve
Next, test these features with Dusk by running the following command to create a new Dusk test:
php artisan dusk:make AuthTest
Navigate to the newly created AuthTest.php
file inside your tests\Browser
directory. You must test both your register and login features.
Create a test that registers a new user, navigates to the dashboard, logs out, and logs back in with the following:
public function testExample()
{
$this->browse(function ($browser) {
//We'll test the register feature here
$browser->visit('/')
->clickLink('Register')
->value('#name', 'Samson')
->value('#email', 'samson@test.com')
->value('#password', '00000000')
->value('#password_confirmation', '00000000')
->click('button[type="submit"]')
//We'll test the login feature here
->press('Samson');
if ($browser->seeLink('Log Out')) {
$browser->clickLink('Log Out')
->clickLink('Login')
->value('#email', 'samson@test.com')
->value('#password', '00000000')
->click('button[type="submit"]');
}
});
}
Here, you are instructing Dusk to visit your application’s homepage, search for a link with the display text Register
, and then click on it. This takes you to the Register page that Jetstream provided.
The value()
function is provided with CSS selectors for the different text boxes as the first argument. The second argument is to fill the values into the text boxes.
click('button[type="submit"]')
clicks the Register button and submits the values you supplied to the database. After this, you are redirected to the dashboard.
With that, the registration works! Now it’s time to log out and test the login feature.
On the top right side of your dashboard, there’s a dropdown list with a Log Out link. Jetstream uses a button for the dropdown; to click on this button using the Dusk method, use press()
.
First, instruct Dusk to find the button with your name as display text and click on it. Next, use an if
statement to check whether there’s a Log Out link on the dropdown list or not. clickLink
clicks the link and redirects to the Welcome page.
clickLink('Login')
selects the Log In link and redirects to the login page. Similar to the register process, use value()
to fill the form. click('button[type="submit"]')
clicks on the LOG IN button and logs back in to the dashboard.
To execute the test, run the following command:
php artisan dusk
Note that Dusk uses headless mode to run automation tests in Google Chrome by default, meaning it works through a CLI rather than a GUI. This means that Dusk runs browser tests, but you don’t see them being executed.
An advantage of using headless mode is that it runs tests faster than using GUI browsers. However, if you want to see your tests being executed in your Chrome browser, you can disable headless mode. Navigate to tests/DuskTestCase.php
and comment out the following lines:
'--disable-gpu',
'--headless',
Now if you run Dusk tests, you’ll see them executed on your Chrome browser.
Finally, you’ve come to the end of this tutorial! If you need the code for the test you created, you can find it on GitHub. To know more about Dusk and the kind of tests you can use it for, check out Dusk’s official documentation.
Original article source at https://blog.logrocket.com
#laravel #php #testing
1651383480
This serverless plugin is a wrapper for amplify-appsync-simulator made for testing AppSync APIs built with serverless-appsync-plugin.
Install
npm install serverless-appsync-simulator
# or
yarn add serverless-appsync-simulator
Usage
This plugin relies on your serverless yml file and on the serverless-offline
plugin.
plugins:
- serverless-dynamodb-local # only if you need dynamodb resolvers and you don't have an external dynamodb
- serverless-appsync-simulator
- serverless-offline
Note: Order is important serverless-appsync-simulator
must go before serverless-offline
To start the simulator, run the following command:
sls offline start
You should see in the logs something like:
...
Serverless: AppSync endpoint: http://localhost:20002/graphql
Serverless: GraphiQl: http://localhost:20002
...
Configuration
Put options under custom.appsync-simulator
in your serverless.yml
file
| option | default | description | | ------------------------ | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | | apiKey | 0123456789
| When using API_KEY
as authentication type, the key to authenticate to the endpoint. | | port | 20002 | AppSync operations port; if using multiple APIs, the value of this option will be used as a starting point, and each other API will have a port of lastPort + 10 (e.g. 20002, 20012, 20022, etc.) | | wsPort | 20003 | AppSync subscriptions port; if using multiple APIs, the value of this option will be used as a starting point, and each other API will have a port of lastPort + 10 (e.g. 20003, 20013, 20023, etc.) | | location | . (base directory) | Location of the lambda functions handlers. | | refMap | {} | A mapping of resource resolutions for the Ref
function | | getAttMap | {} | A mapping of resource resolutions for the GetAtt
function | | importValueMap | {} | A mapping of resource resolutions for the ImportValue
function | | functions | {} | A mapping of external functions for providing invoke url for external fucntions | | dynamoDb.endpoint | http://localhost:8000 | Dynamodb endpoint. Specify it if you're not using serverless-dynamodb-local. Otherwise, port is taken from dynamodb-local conf | | dynamoDb.region | localhost | Dynamodb region. Specify it if you're connecting to a remote Dynamodb intance. | | dynamoDb.accessKeyId | DEFAULT_ACCESS_KEY | AWS Access Key ID to access DynamoDB | | dynamoDb.secretAccessKey | DEFAULT_SECRET | AWS Secret Key to access DynamoDB | | dynamoDb.sessionToken | DEFAULT_ACCESS_TOKEEN | AWS Session Token to access DynamoDB, only if you have temporary security credentials configured on AWS | | dynamoDb.* | | You can add every configuration accepted by DynamoDB SDK | | rds.dbName | | Name of the database | | rds.dbHost | | Database host | | rds.dbDialect | | Database dialect. Possible values (mysql | postgres) | | rds.dbUsername | | Database username | | rds.dbPassword | | Database password | | rds.dbPort | | Database port | | watch | - *.graphql
- *.vtl | Array of glob patterns to watch for hot-reloading. |
Example:
custom:
appsync-simulator:
location: '.webpack/service' # use webpack build directory
dynamoDb:
endpoint: 'http://my-custom-dynamo:8000'
Hot-reloading
By default, the simulator will hot-relad when changes to *.graphql
or *.vtl
files are detected. Changes to *.yml
files are not supported (yet? - this is a Serverless Framework limitation). You will need to restart the simulator each time you change yml files.
Hot-reloading relies on watchman. Make sure it is installed on your system.
You can change the files being watched with the watch
option, which is then passed to watchman as the match expression.
e.g.
custom:
appsync-simulator:
watch:
- ["match", "handlers/**/*.vtl", "wholename"] # => array is interpreted as the literal match expression
- "*.graphql" # => string like this is equivalent to `["match", "*.graphql"]`
Or you can opt-out by leaving an empty array or set the option to false
Note: Functions should not require hot-reloading, unless you are using a transpiler or a bundler (such as webpack, babel or typescript), un which case you should delegate hot-reloading to that instead.
Resource CloudFormation functions resolution
This plugin supports some resources resolution from the Ref
, Fn::GetAtt
and Fn::ImportValue
functions in your yaml file. It also supports some other Cfn functions such as Fn::Join
, Fb::Sub
, etc.
Note: Under the hood, this features relies on the cfn-resolver-lib package. For more info on supported cfn functions, refer to the documentation
You can reference resources in your functions' environment variables (that will be accessible from your lambda functions) or datasource definitions. The plugin will automatically resolve them for you.
provider:
environment:
BUCKET_NAME:
Ref: MyBucket # resolves to `my-bucket-name`
resources:
Resources:
MyDbTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: myTable
...
MyBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: my-bucket-name
...
# in your appsync config
dataSources:
- type: AMAZON_DYNAMODB
name: dynamosource
config:
tableName:
Ref: MyDbTable # resolves to `myTable`
Sometimes, some references cannot be resolved, as they come from an Output from Cloudformation; or you might want to use mocked values in your local environment.
In those cases, you can define (or override) those values using the refMap
, getAttMap
and importValueMap
options.
refMap
takes a mapping of resource name to value pairsgetAttMap
takes a mapping of resource name to attribute/values pairsimportValueMap
takes a mapping of import name to values pairsExample:
custom:
appsync-simulator:
refMap:
# Override `MyDbTable` resolution from the previous example.
MyDbTable: 'mock-myTable'
getAttMap:
# define ElasticSearchInstance DomainName
ElasticSearchInstance:
DomainEndpoint: 'localhost:9200'
importValueMap:
other-service-api-url: 'https://other.api.url.com/graphql'
# in your appsync config
dataSources:
- type: AMAZON_ELASTICSEARCH
name: elasticsource
config:
# endpoint resolves as 'http://localhost:9200'
endpoint:
Fn::Join:
- ''
- - https://
- Fn::GetAtt:
- ElasticSearchInstance
- DomainEndpoint
In some special cases you will need to use key-value mock nottation. Good example can be case when you need to include serverless stage value (${self:provider.stage}
) in the import name.
This notation can be used with all mocks - refMap
, getAttMap
and importValueMap
provider:
environment:
FINISH_ACTIVITY_FUNCTION_ARN:
Fn::ImportValue: other-service-api-${self:provider.stage}-url
custom:
serverless-appsync-simulator:
importValueMap:
- key: other-service-api-${self:provider.stage}-url
value: 'https://other.api.url.com/graphql'
This plugin only tries to resolve the following parts of the yml tree:
provider.environment
functions[*].environment
custom.appSync
If you have the need of resolving others, feel free to open an issue and explain your use case.
For now, the supported resources to be automatically resovled by Ref:
are:
Feel free to open a PR or an issue to extend them as well.
External functions
When a function is not defined withing the current serverless file you can still call it by providing an invoke url which should point to a REST method. Make sure you specify "get" or "post" for the method. Default is "get", but you probably want "post".
custom:
appsync-simulator:
functions:
addUser:
url: http://localhost:3016/2015-03-31/functions/addUser/invocations
method: post
addPost:
url: https://jsonplaceholder.typicode.com/posts
method: post
Supported Resolver types
This plugin supports resolvers implemented by amplify-appsync-simulator
, as well as custom resolvers.
From Aws Amplify:
Implemented by this plugin
#set( $cols = [] )
#set( $vals = [] )
#foreach( $entry in $ctx.args.input.keySet() )
#set( $regex = "([a-z])([A-Z]+)")
#set( $replacement = "$1_$2")
#set( $toSnake = $entry.replaceAll($regex, $replacement).toLowerCase() )
#set( $discard = $cols.add("$toSnake") )
#if( $util.isBoolean($ctx.args.input[$entry]) )
#if( $ctx.args.input[$entry] )
#set( $discard = $vals.add("1") )
#else
#set( $discard = $vals.add("0") )
#end
#else
#set( $discard = $vals.add("'$ctx.args.input[$entry]'") )
#end
#end
#set( $valStr = $vals.toString().replace("[","(").replace("]",")") )
#set( $colStr = $cols.toString().replace("[","(").replace("]",")") )
#if ( $valStr.substring(0, 1) != '(' )
#set( $valStr = "($valStr)" )
#end
#if ( $colStr.substring(0, 1) != '(' )
#set( $colStr = "($colStr)" )
#end
{
"version": "2018-05-29",
"statements": ["INSERT INTO <name-of-table> $colStr VALUES $valStr", "SELECT * FROM <name-of-table> ORDER BY id DESC LIMIT 1"]
}
#set( $update = "" )
#set( $equals = "=" )
#foreach( $entry in $ctx.args.input.keySet() )
#set( $cur = $ctx.args.input[$entry] )
#set( $regex = "([a-z])([A-Z]+)")
#set( $replacement = "$1_$2")
#set( $toSnake = $entry.replaceAll($regex, $replacement).toLowerCase() )
#if( $util.isBoolean($cur) )
#if( $cur )
#set ( $cur = "1" )
#else
#set ( $cur = "0" )
#end
#end
#if ( $util.isNullOrEmpty($update) )
#set($update = "$toSnake$equals'$cur'" )
#else
#set($update = "$update,$toSnake$equals'$cur'" )
#end
#end
{
"version": "2018-05-29",
"statements": ["UPDATE <name-of-table> SET $update WHERE id=$ctx.args.input.id", "SELECT * FROM <name-of-table> WHERE id=$ctx.args.input.id"]
}
{
"version": "2018-05-29",
"statements": ["UPDATE <name-of-table> set deleted_at=NOW() WHERE id=$ctx.args.id", "SELECT * FROM <name-of-table> WHERE id=$ctx.args.id"]
}
#set ( $index = -1)
#set ( $result = $util.parseJson($ctx.result) )
#set ( $meta = $result.sqlStatementResults[1].columnMetadata)
#foreach ($column in $meta)
#set ($index = $index + 1)
#if ( $column["typeName"] == "timestamptz" )
#set ($time = $result["sqlStatementResults"][1]["records"][0][$index]["stringValue"] )
#set ( $nowEpochMillis = $util.time.parseFormattedToEpochMilliSeconds("$time.substring(0,19)+0000", "yyyy-MM-dd HH:mm:ssZ") )
#set ( $isoDateTime = $util.time.epochMilliSecondsToISO8601($nowEpochMillis) )
$util.qr( $result["sqlStatementResults"][1]["records"][0][$index].put("stringValue", "$isoDateTime") )
#end
#end
#set ( $res = $util.parseJson($util.rds.toJsonString($util.toJson($result)))[1][0] )
#set ( $response = {} )
#foreach($mapKey in $res.keySet())
#set ( $s = $mapKey.split("_") )
#set ( $camelCase="" )
#set ( $isFirst=true )
#foreach($entry in $s)
#if ( $isFirst )
#set ( $first = $entry.substring(0,1) )
#else
#set ( $first = $entry.substring(0,1).toUpperCase() )
#end
#set ( $isFirst=false )
#set ( $stringLength = $entry.length() )
#set ( $remaining = $entry.substring(1, $stringLength) )
#set ( $camelCase = "$camelCase$first$remaining" )
#end
$util.qr( $response.put("$camelCase", $res[$mapKey]) )
#end
$utils.toJson($response)
Variable map support is limited and does not differentiate numbers and strings data types, please inject them directly if needed.
Will be escaped properly: null
, true
, and false
values.
{
"version": "2018-05-29",
"statements": [
"UPDATE <name-of-table> set deleted_at=NOW() WHERE id=:ID",
"SELECT * FROM <name-of-table> WHERE id=:ID and unix_timestamp > $ctx.args.newerThan"
],
variableMap: {
":ID": $ctx.args.id,
## ":TIMESTAMP": $ctx.args.newerThan -- This will be handled as a string!!!
}
}
Requires
Author: Serverless-appsync
Source Code: https://github.com/serverless-appsync/serverless-appsync-simulator
License: MIT License
1648972740
Generis
Versatile Go code generator.
Generis is a lightweight code preprocessor adding the following features to the Go language :
package main;
// -- IMPORTS
import (
"html"
"io"
"log"
"net/http"
"net/url"
"strconv"
);
// -- DEFINITIONS
#define DebugMode
#as true
// ~~
#define HttpPort
#as 8080
// ~~
#define WriteLine( {{text}} )
#as log.Println( {{text}} )
// ~~
#define local {{variable}} : {{type}};
#as var {{variable}} {{type}};
// ~~
#define DeclareStack( {{type}}, {{name}} )
#as
// -- TYPES
type {{name}}Stack struct
{
ElementArray []{{type}};
}
// -- INQUIRIES
func ( stack * {{name}}Stack ) IsEmpty(
) bool
{
return len( stack.ElementArray ) == 0;
}
// -- OPERATIONS
func ( stack * {{name}}Stack ) Push(
element {{type}}
)
{
stack.ElementArray = append( stack.ElementArray, element );
}
// ~~
func ( stack * {{name}}Stack ) Pop(
) {{type}}
{
local
element : {{type}};
element = stack.ElementArray[ len( stack.ElementArray ) - 1 ];
stack.ElementArray = stack.ElementArray[ : len( stack.ElementArray ) - 1 ];
return element;
}
#end
// ~~
#define DeclareStack( {{type}} )
#as DeclareStack( {{type}}, {{type:PascalCase}} )
// -- TYPES
DeclareStack( string )
DeclareStack( int32 )
// -- FUNCTIONS
func HandleRootPage(
response_writer http.ResponseWriter,
request * http.Request
)
{
local
boolean : bool;
local
natural : uint;
local
integer : int;
local
real : float64;
local
escaped_html_text,
escaped_url_text,
text : string;
local
integer_stack : Int32Stack;
boolean = true;
natural = 10;
integer = 20;
real = 30.0;
text = "text";
escaped_url_text = "&escaped text?";
escaped_html_text = "<escaped text/>";
integer_stack.Push( 10 );
integer_stack.Push( 20 );
integer_stack.Push( 30 );
#write response_writer
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title><%= request.URL.Path %></title>
</head>
<body>
<% if ( boolean ) { %>
<%= "URL : " + request.URL.Path %>
<br/>
<%@ natural %>
<%# integer %>
<%& real %>
<br/>
<%~ text %>
<%^ escaped_url_text %>
<%= escaped_html_text %>
<%= "<%% ignored %%>" %>
<%% ignored %%>
<% } %>
<br/>
Stack :
<br/>
<% for !integer_stack.IsEmpty() { %>
<%# integer_stack.Pop() %>
<% } %>
</body>
</html>
#end
}
// ~~
func main()
{
http.HandleFunc( "/", HandleRootPage );
#if DebugMode
WriteLine( "Listening on http://localhost:HttpPort" );
#end
log.Fatal(
http.ListenAndServe( ":HttpPort", nil )
);
}
Constants and generic code can be defined with the following syntax :
#define old code
#as new code
#define old code
#as
new
code
#end
#define
old
code
#as new code
#define
old
code
#as
new
code
#end
The #define
directive can contain one or several parameters :
{{variable name}} : hierarchical code (with properly matching brackets and parentheses)
{{variable name#}} : statement code (hierarchical code without semicolon)
{{variable name$}} : plain code
{{variable name:boolean expression}} : conditional hierarchical code
{{variable name#:boolean expression}} : conditional statement code
{{variable name$:boolean expression}} : conditional plain code
They can have a boolean expression to require they match specific conditions :
HasText text
HasPrefix prefix
HasSuffix suffix
HasIdentifier text
false
true
!expression
expression && expression
expression || expression
( expression )
The #define
directive must not start or end with a parameter.
The #as
directive can use the value of the #define
parameters :
{{variable name}}
{{variable name:filter function}}
{{variable name:filter function:filter function:...}}
Their value can be changed through one or several filter functions :
LowerCase
UpperCase
MinorCase
MajorCase
SnakeCase
PascalCase
CamelCase
RemoveComments
RemoveBlanks
PackStrings
PackIdentifiers
ReplacePrefix old_prefix new_prefix
ReplaceSuffix old_suffix new_suffix
ReplaceText old_text new_text
ReplaceIdentifier old_identifier new_identifier
AddPrefix prefix
AddSuffix suffix
RemovePrefix prefix
RemoveSuffix suffix
RemoveText text
RemoveIdentifier identifier
Conditional code can be defined with the following syntax :
#if boolean expression
#if boolean expression
...
#else
...
#end
#else
#if boolean expression
...
#else
...
#end
#end
The boolean expression can use the following operators :
false
true
!expression
expression && expression
expression || expression
( expression )
Templated HTML code can be sent to a stream writer using the following syntax :
#write writer expression
<% code %>
<%@ natural expression %>
<%# integer expression %>
<%& real expression %>
<%~ text expression %>
<%= escaped text expression %>
<%! removed content %>
<%% ignored tags %%>
#end
--join
option requires to end the statements with a semicolon.#writer
directive is only available for the Go language.Install the DMD 2 compiler (using the MinGW setup option on Windows).
Build the executable with the following command line :
dmd -m64 generis.d
generis [options]
--prefix # : set the command prefix
--parse INPUT_FOLDER/ : parse the definitions of the Generis files in the input folder
--process INPUT_FOLDER/ OUTPUT_FOLDER/ : reads the Generis files in the input folder and writes the processed files in the output folder
--trim : trim the HTML templates
--join : join the split statements
--create : create the output folders if needed
--watch : watch the Generis files for modifications
--pause 500 : time to wait before checking the Generis files again
--tabulation 4 : set the tabulation space count
--extension .go : generate files with this extension
generis --process GS/ GO/
Reads the Generis files in the GS/
folder and writes Go files in the GO/
folder.
generis --process GS/ GO/ --create
Reads the Generis files in the GS/
folder and writes Go files in the GO/
folder, creating the output folders if needed.
generis --process GS/ GO/ --create --watch
Reads the Generis files in the GS/
folder and writes Go files in the GO/
folder, creating the output folders if needed and watching the Generis files for modifications.
generis --process GS/ GO/ --trim --join --create --watch
Reads the Generis files in the GS/
folder and writes Go files in the GO/
folder, trimming the HTML templates, joining the split statements, creating the output folders if needed and watching the Generis files for modifications.
2.0
Author: Senselogic
Source Code: https://github.com/senselogic/GENERIS
License: View license
1598916060
The demand for delivering quality software faster — or “Quality at Speed” — requires organizations to search for solutions in Agile, continuous integration (CI), and DevOps methodologies. Test automation is an essential part of these aspects. The latest World Quality Report 2018–2019 suggests that test automation is the biggest bottleneck to deliver “Quality at Speed,” as it is an enabler of successful Agile and DevOps adoption.
Test automation cannot be realized without good tools; as they determine how automation is performed and whether the benefits of automation can be delivered. Test automation tools is a crucial component in the DevOps toolchain. The current test automation trends have increased in applying artificial intelligence and machine learning (AI/ML) to offer advanced capabilities for test optimization, intelligent test generation, execution, and reporting. It will be worthwhile to understand which tools are best poised to take advantage of these trends.****
#automation-testing #automation-testing-tools #testing #testing-tools #selenium #open-source #test-automation #automated-testing
1596793726
What do you do when you have lots of free time on your hands? Why not learn test programming strategies and approaches?
When you’re looking for places to learn test programming, Test Automation University has you covered. From API testing through visual validation, you can hone your skills and learn new approaches on TAU.
We introduced five new TAU courses from April through June, and each of them can help you expand your knowledge, learn a new approach, and improve your craft as a test automation engineer. They are:
These courses add to the other three courses we introduced in January through March 2020:
Each of these courses can give you a new set of skills.
Let’s look at each in a little detail.
Orane Findley teaches Mobile Automation with Appium in JavaScript. Orane walks through all the basics of Appium, starting with what it is and where it runs.
“Appium is an open-source tool for automating native, web, and hybrid applications on different platforms.”
In the introduction, Orane describes the course parts:
The first chapter, broken into five parts, gets your system ready for the rest of the course. You’ll download and install a Java Developer Kit, a stable version of Node.js, Android Studio and Emulator (for a mobile device emulator), Visual Studio Code for an IDE, Appium Server, and a sample Appium Android Package Kit. If you get into trouble, you can use the Test Automation University Slack channel to get help from Orane. Each subchapter contains the links to get to the proper software. Finally, Orane has you customize your configuration for the course project.
Chapter 2 deals with elements and screen interactions for your app. You can find elements on the page, interact with those elements, and scroll the page to make other elements visible. Orane breaks the chapter into three distinct subchapters so you can become competent with each part of finding, scrolling, and interacting with the app. The quiz comes at the end of the third subchapter.
The remaining chapters each deal with specific bullets listed above: sessions and screen capture, timing, element attributes, and using element states. The final summary chapter ensures you have internalized the key takeaways from the course. Each of these chapters includes its quiz.
When you complete this course successfully, you will have both a certificate of completion and the code infrastructure available on your system to start testing mobile apps using Appium.
Andrew Knight, who blogs as The Automation Panda, teaches the course on Selenium WebDriver with Python. As Andrew points out, Python has become a popular language for test automation. If you don’t know Python at all, he points you to Jess Ingrassellino’s great course, Python for Test Programming, also on Test Automation University.
In the first chapter, Andrew has you write your first test. Not in Python, but Gherkin. If you have never used Gherkin syntax, it helps you structure your tests in pseudocode that you can translate into any language of your choice. Andrew points out that it’s important to write your test steps before you write test code — and Gherkin makes this process straightforward.
The second chapter goes through setting up a pytest, the test framework Andrew uses. He assumes you already have Python 3.8 installed. Depending on your machine, you may need to do some work (Macs come with Python 2.7.16 installed, which is old and won’t work. Andrew also goes through the pip package manager to install pipenv. He gives you a GitHub link to his test code for the project. And, finally, he creates a test using the Gherkin codes as comments to show you how a test runs in pytest.
In the third chapter, you set up Selenium Webdriver to work with specific browsers, then create your test fixture in the pytest. Andrew reminds you to download the appropriate browser driver for the browser you want to test — for example, chromedriver to drive Chrome and geckodriver to drive Firefox. Once you use pipenv to install Selenium, you begin your test fixture. One thing to remember is to call an explicit quit for your webdriver after a test.
Chapter 4 goes through page objects, and how you abstract page object details to simplify your test structure. Chapter 5 goes through element locator structures and how to use these in Python. And, in Chapter 6, Andrew goes through some common webdriver calls and how to use them in your tests. These first six chapters cover the basics of testing with Python and Selenium.
Now that you have the basics down, the final three chapters review some advanced ideas: testing with multiple browsers, handling race conditions, and running your tests in parallel. This course gives you specific skills around Python and Selenium on top of what you can get from the Python for Test Programming course.
#tutorial #performance #testing #automation #test automation #automated testing #visual testing #visual testing best practices #testing tutorial
1596797400
I’m a Developer Advocate and one of the things I love most about my role is that I travel all of over the world — meeting and consulting with engineering teams, and discussing the challenges that they face.
One thing that I’ve realized about building quality software is…the struggle is real!
Everyone is trying to figure out how to rapidly-produce software that is yet of high quality. So we did some research (shout out to Moshe Milman who helped with this effort) and gathered best practices from some of the top companies in software, financial services, healthcare, gaming, and entertainment verticals and I’ll share with you what these innovative development teams are doing to achieve great levels of success with their test automation initiatives.
As I go through the points of research, feel free to grade your team’s maturity in that respective area. By the end of the article, you’ll have your Test Automation Maturity Level.
100% of companies researched automate their tests
For starters, 100% of the companies we researched employ automated tests to expedite their release cycles. When the goal is to release software on a continuous cycle, test automation is a must-have. There simply isn’t enough time to manually test every new feature as well as manually execute regression tests to make sure existing functionality isn’t broken. So these teams invest an extensive amount of effort into automating their tests so that they are confident in their product each time they deploy.
Percentages showing who on the team is responsible for writing tests
I know from personal experience how difficult it is for developers to find the time to write tests and also how difficult it is to have test teams write the code to automate tests, so we inquired about this a bit more to determine how are teams overcoming these challenges.
Every single one of these companies has its developers involved in writing tests. Many of them said their developers take care of the unit tests, while the QA team is responsible for writing the integration and end-to-end tests.
A whopping 60% of the teams shared that they no longer have the distinction between development and QA engineers, and instead have hybrid engineers. Their goal here is to have developers own ALL the testing of their code, as well as the triaging and maintenance of those tests.
What they discovered is what I already know — developers aren’t the best at this. There’s not much time, and frankly not much interest from developers to go beyond writing their unit tests. So, many of these teams have had to bring in qualified experts to help out.
I dug a bit more to learn how exactly the Quality Advocates are assisting here. We got a variety of answers but here were some of the common ones:
Let’s discuss each of these…
Write Test Infrastructure
The Quality Advocates find the best testing libraries, create the test automation codebase, and all of the utility functionality the developers will need to write their tests. That way it’s not much overhead for the developers. The developers can just focus on cranking their tests out.
Unfortunately, many of the Computer Science and Bootcamp programs that graduated your developers did not teach them how to test. This is a huge hurdle for developers who may have good intentions and want to test their code. They may not ever share this with you, but a LOT of the developers that I speak with simply don’t know how to test. These quality advocates specialize in this stuff and can help the developers think of scenarios, as well as teach them how to write good tests. If you think this may be a problem for your developers and you don’t have a quality advocate just yet, send them to Test Automation University which is an online learning platform that provides free courses on this very thing.
Finally, quality advocates develop testing strategies for the team. They help them assess risk and come up with a plan of attack on what should be tested and how thoroughly.
They also have a big picture view which is greatly needed because your developers are zoned in on their features and their tests. Someone needs to consider how these features interact with one another so that more sophisticated tests can be developed.
Someone also needs to strategize on which tests automatically run given certain pull requests. The advocate can help with that.
The quality advocates also help keep the test suites relevant by pruning out tests that are no longer of high business value.
If your team automates _any _tests at all, go ahead and give yourself 10 points!
We wanted to make sure that we were talking about more than unit tests here, so we inquired about which tests the companies automated.
Give yourself 10 points for each of the types you automate: unit, web/mobile, API, security, performance, and accessibility. If your team does not develop mobile apps, just give yourself 10 points so that you don’t have a deficit. The same goes for if your company does not develop web apps or APIs.
I did some research last year on the top programming languages used in test automation. This included all sorts of companies, not just the mature top dogs. The vast majority of teams are using Java (44%) and while JavaScript was on the rise and came in at #2, it was still only 15%.
This was interesting compared to what the top dogs are using. ALL of them use JavaScript! Some have teams that use other languages in addition to JavaScript for things like native mobile testing and APIs, but for their web apps, it’s JavaScript.
Programming languages used for test automation
I inquired why this is and they explained that their web developers are JavaScript programmers. Some companies even said they had legacy test frameworks built in other languages and their devs wouldn’t touch it! When they switched to JavaScript, the developers became more engaged.
I found this interesting because it aligns with what some thought leaders have been preaching for years. I’ll admit, I’ve been a bit stubborn over my career and I tend to go for the language that the automation will be most comfortable in but it seems perhaps I need to rethink that when I want the developers to contribute.
And to be fair, JavaScript automation tools have gotten much better in recent years…which brings me to the next point of research…
#tutorial #performance #testing #programming #automation #test automation #automated testing #qa #automated testing best practices