SlideShare ist ein Scribd-Unternehmen logo
1 von 79
Downloaden Sie, um offline zu lesen
KAKUNIN
E2E REINVENTED
ADAM POLAK
PHP DEVELOPER
JS DEVELOPER
E2E DEVELOPER
E2E DEVELOPER
JS DEVELOPER
TOMASZ GÓRSKI
KAKUNIN WORKSHOPS
AGENDA
▸ HOW TO INSTALL AND CONFIGURE KAKUNIN?
▸ HOW TO NAVIGATE BETWEEN PAGES AND
VALIDATE CURRENT PAGE?
▸ HOW TO INTERACT WITH ELEMENTS AND
VALIDATE CONTENT?
▸ HOW TO FILL IN, CHECK OUT ITS VALUES AND
VALIDATE FORMS?
▸ HOW TO CHECK EMAILS CONTENT?
▸ HOW TO DEBUG KAKUNIN?
KAKUNIN WORKSHOPS
▸ HOW TO EXTEND KAKUNIN WITH CUSTOM STEPS?
▸ HOW TO HANDLE NON-BUILT-IN FORM FIELD
TYPES?
▸ HOW TO ADD SCENARIO SPECIFIC HOOKS?
▸ HOW TO CONNECT DIFFERENT MAILING SERVICE?
AGENDA
WHAT IS KAKUNIN?
KAKUNIN WORKSHOPS
WHAT IS KAKUNIN?
▸ PROTRACTOR EXTENSION
▸ GHERKIN AS A PROGRAMMING LANGUAGE
▸ BUILT-IN STEPS TO SOLVE MOST COMMON CASES
▸ EASLY EXTENDABLE
▸ HANDLES ANGULAR AND NON-ANGULAR APPS
OUT OF THE BOX
KAKUNIN
WHAT ARE WE GOING TO
TEST?
KAKUNIN WORKSHOPS
INSTALATION
HOW TO INSTALL?
{
"name": "workshop",
"version": "0.0.1",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"author": "",
"license": "ISC"
}
cd kakunin-workshop
mkdir kakunin-workshop
npm init
INSTALATION
HOW TO INSTALL?
npm install webdriver-manager

npm install protractor

npm install kakunin
{
...
"scripts": {
...
"kakunin": "NODE_ENV=prod kakunin"
},
...
"devDependencies": {
...

"webdriver-manager": "12.0.6",
"protractor": "5.1.2",
"kakunin": "1.0.1"
}
}
INSTALATION
HOW TO INSTALL?
npm run kakunin init
cd step_definitions

ln -s ../node_modules/kakunin/dist/step_definitions/elements.js kakunin-elements.js
ln -s ../node_modules/kakunin/dist/step_definitions/debug.js kakunin-debug.js
ln -s ../node_modules/kakunin/dist/step_definitions/file.js kakunin-file.js
ln -s ../node_modules/kakunin/dist/step_definitions/form.js kakunin-form.js
ln -s ../node_modules/kakunin/dist/step_definitions/email.js kakunin-email.js
ln -s ../node_modules/kakunin/dist/step_definitions/generators.js kakunin-generators.js
ln -s ../node_modules/kakunin/dist/step_definitions/navigation.js kakunin-navigation.js
INSTALATION
HOW TO INSTALL?
npm run kakunin
Scenario:
If you can see this in console then hook is working properly.
✔ When I visit the "page" page
✔ And I generate random "name" as "myName"
✔ Then my matcher "e:name" matches "v:myName"
✔ And my matcher "e:name" matches "Bob"
1 scenario (1 passed)
4 steps (4 passed)
0m00.757s
INSTALATION
HOW TO RUN A SINGLE SCENARIO?
npm run kakunin -- --tags @someTag
npm run kakunin -- --tags="@someTag and @otherTag"
npm run kakunin -- --tags="@someTag or @otherTag"
npm run kakunin -- --tags="not @someTag"
NAVIGATE BETWEEN
PAGES
KAKUNIN WORKSHOPS
NAVIGATE BETWEEN PAGES
PAGE OBJECT
const { BasePage } = require('kakunin');
class MainPage extends BasePage {
constructor() {
super();
this.url = '/';
}
}
module.exports = new MainPage();
NAVIGATE BETWEEN PAGES
SCENARIO - NAVIGATING
Feature: Load main page
Scenario: Load main page as homepage
Given/When I visit the "main" page
The name of a page object file. For this case there has to be a file "main.js" in pages directory.
NAVIGATE BETWEEN PAGES
SCENARIO - CHECKING OUT ON WHAT PAGE WE ARE
Then the "main" page is displayed
The name of a page object file. For this case there has to be a file "main.js" in pages directory.
NAVIGATE BETWEEN PAGES
SCENARIO - DEBUGGING
Give/When/Then I wait for "20" seconds
Give/When/Then I pause
NAVIGATE BETWEEN PAGES
WHAT ABOUT URL WITH PARAMETERS ?
/suppliers/some-supplier-id/clients/some-client-id
/suppliers/:supplierId/clients/:clientId
...
this.url = '/suppliers/:supplierId/clients/:clientId';
...
NAVIGATE BETWEEN PAGES
PAGE CONTEXT
Then the "main" page is displayed
EVERY BUILT-IN STEP (EXCEPT NAVIGATION
ONES) WILL HAVE AN ACCESS TO MAIN PAGE
OBJECT.
INTERACTING WITH
ELEMENTS
INTERACTING WITH ELEMENTS
INTERACTING WITH ELEMENTS
Then the "showActive" element is visible
The name of a selector from current page object file.
ELEMENT VISIBILITY
INTERACTING WITH ELEMENTS
SELECTORS
▸ defines access to element
▸ support for protractor locators

http://www.protractortest.org/#/api?
view=ProtractorBy
▸ support for angular only attributes
INTERACTING WITH ELEMENTS
SELECTORS
▸ id attribute, custom attribute, custom class, unique class - GOOD
▸ for angular app: ng-model, ng-repeat - GOOD
▸ html tag - BAD
▸ angular validation classes (ng-valid, ng-pristine etc) - VERY BAD
INTERACTING WITH ELEMENTS
SELECTORS
this.mySelectorName = $('.css-selector');
this.mySelectorName = $('html-tag');
this.mySelectorName = $('html-tag.css-selector');
this.mySelectorName = element(by.repeater('project in projects'));
INTERACTING WITH ELEMENTS
Then the "showActive" element is visible
ELEMENT VISIBILITY - PROBLEM
THE ELEMENT MUST BE VISIBLE RIGHT AWAY.
IT DOES NOT WAIT FOR ELEMENT TO BE
VISIBLE.
INTERACTING WITH ELEMENTS
When/Given/Then I wait for "visibilityOf" of the "showActive" element
ELEMENT VISIBILITY - SOLUTION
uses protractors expected conditions internally, for example
visibilityOf
invisibilityOf
INTERACTING WITH ELEMENTS
ELEMENT VISIBILITY - WHAT ELSE?
When/Given/Then the "showCompleted" element is present
When/Given/Then the "showCompleted" element is not visible
When/Given/Then the "showCompleted" element is not present
INTERACTING WITH ELEMENTS
When I fill the "myForm" form with:
| fieldSelector | value to be used |
Form selector
Input selector
this.myForm = $('.add-todo');
this.fieldSelector = $('.add-todo input[name="add-todo"]');
FILLING UP FORM
INTERACTING WITH ELEMENTS
Then the "myForm" form is filled with:
| fieldSelector | value to be used |
Form selector
Input selector
CHECKING OUT FORM VALUE
INTERACTING WITH ELEMENTS
WHAT ABOUT DIFFERENT FIELD TYPES?
▸ supports all of the basic html field types (radio, checkbox, textarea, select, file, text)
▸ allows to add custom made handlers for field types
INTERACTING WITH ELEMENTS
HOW ABOUT SUBMITTING ?
When I click the "addTodoButton" element
The name of a selector from current page object file.
CUSTOM STEPS
CUSTOM STEPS
CUSTOM STEPS
OUR STEP
Given I am logged in as an "submitter"
User role
CUSTOM STEPS
CUCUMBER 2.0 - STEP DEFINITION
const { defineSupportCode } = require('kakunin');
defineSupportCode(({ Given }) => {
Given(/^I am logged in as an "([^"]*)"$/, function (user) {
return Promise.resolve();
});
});
CUSTOM STEPS
ACCESS PAGE FROM CODE
const myPage = browser.page.myPage;
CUSTOM STEPS
BASE PAGE METHODS
visit()
click(elementSelectorName)
isDisabled(elementSelectorName)
isPresent(elementSelectorName)
isVisible(elementSelectorName)
isOn()
CUSTOM STEPS
BASE PAGE METHODS
getNumberOfElements(elementSelectorName)
scrollIntoElement(elementSelectorName, optionalIndexForArrayElement)
CUSTOM STEPS
BASE PAGE METHODS
fillForm(formData)
[
[
'fieldSelector',
'fieldValue'
]
]
checkForm(formData)
[
[
'fieldSelector',
'fieldValue'
]
]
CUSTOM STEPS
BASE PAGE METHODS
fillField(fieldSelector, fiedlValue)
checkField(fieldSelector, fiedlValue)
EVERY METHOD RETURNS A PROMISE
CUSTOM STEPS
USER PROVIDER
this.userProvider.getUser(userName);
accounts: {
userName: {
accounts: [
{
email: 'some@email.com',
password: 'somePassword'
}
]
}

}
CUSTOM STEPS
USER PROVIDER
this.currentUser = {
account: {
email: 'some@email.com',
password: 'somePassword'
},
type: "userName"
}
HOOKS
HOOKS
HOOKS
HOOK DEFINITION
const { defineSupportCode } = require('kakunin');
defineSupportCode(({ After }) => {
After(() => {

return Promise.resolve();

});
});
defineSupportCode(({ After }) => {
After('@someTag', () => {

return Promise.resolve();

});
});
HOOKS
HOOK DEFINITION - EXECUTE REMOTE JS CODE
protractor.browser.executeScript('your js code to be run inside a browser');
HOOKS
HOOK DEFINITION - CLEAR COOKIES
protractor.browser.manage().deletAllCookies();
HOOKS
RESTORE APP STATE
FIXTURES_RELOAD_HOST=http://192.168.99.100/app_e2e.php/_e2e/load_fixtures
@reloadFixtures
CUSTOM HANDLERS
HANDLERS
CUSTOM HANDLERS
INTERFACE
isSatisfiedBy(element, elementName) {
return Promise.resolve();
}
handleFill(page, elementName, desiredValue) {
return Promise.resolve();
}
handleCheck(page, elementName, desiredValue) {
return Promise.resolve();
}
getPriority() {
return 1000;
}
CUSTOM HANDLERS
HANDLER SERVICE - ADDING NEW HANDLER
const { handlers } = require('kakunin');
class MyHandler {}
handler.addHandler(new MyHandler());
CUSTOM HANDLERS
CUSTOM SELECT HTML
<div class="form__field serviceMarket form__field--danger">
<label class="form__label form__label--required">Service Market</label>
<div class="Select Select--single is-clearable is-focused is-open">
<div class="Select-control">
</div>
<div class="Select-menu-outer">
<div role="listbox" class="Select-menu">
<div style="overflow: visible; width: 0px;">
<div aria-label="grid" class="ReactVirtualized__Grid ReactVirtualized__List
VirtualSelectGrid">
<div class="ReactVirtualized__Grid__innerScrollContainer">
<div class="select__option" data-e2e="/app_e2e.php/service_markets/
80a06089-2f94-4992-8f7c-1d30fc7b8a3e">SME Services</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
CUSTOM HANDLERS
CUSTOM SELECT HTML - SELECTED OPTION
<div class="form__field serviceMarket">
<label class="form__label form__label--required">Service Market</label>
<div class="Select Select--single is-clearable has-value">
<input type="hidden" name="serviceMarket" value="/app_e2e.php/service_markets/
80a06089-2f94-4992-8f7c-1d30fc7b8a3e">
</div>
</div>
TRANSFORMERS
TRANSFORMERS
TRANSFORMERS
A WAY TO GENERATE OR TRANSFORM VALUES FROM

HUMAN READABLE VERSION TO APP USABLE.
TRANSFORMERS
g:generatorName:param1:param2:param...N
AVAILABLE TRANSFORMERS
d:dictionaryName:dictionaryKeyName
v:variableName
TRANSFORMERS
When I fill the "myForm" form with:
| projectUrl | http://some-url.com |
| projectType | 1234 |
WITHOUT TRANSFORMERS
When I fill the "myForm" form with:
| projectUrl | g:projectUrl |
| projectType | d:projectTypes:website |
WITH TRANSFORMERS
TRANSFORMERS
GENERATORS
const { generators } = require('kakunin');
class ProjectUrlGenerator{
isSatisfiedBy(name) {
return this.name === 'projectUrl';
}
generate(params) {
return Promise.resolve('http://some-url.pl');
}
}
generators.addGenerator(new ProjectUrlGenerator());
TRANSFORMERS
DICTIONARIES
const { dictionaries } = require('kakunin');
class ProjectTypesDictionary{
constructor() {
this.values = {
'myServiceMarket':'/service_markets/80a06089-2f94-4992-8f7c-1d30fc7b8a3e'
};
this.name = 'projectTypes';
}
isSatisfiedBy(name) {
return this.name === name;
}
getMappedValue(key) {
return this.values[key];
}
}
dictionaries.addDictionary(new ProjectTypesDictionary());
EMAILS
EMAILS
EMAILS
CONFIGURATION
email: {
type: 'mailtrap',
config: {
apiKey: '81279e9fb9351ebdf7aefef89e6a5701',
inboxId: '203459',
url: 'https://mailtrap.io/api/v1'
}
},
clearEmailInboxBeforeTests: true
mailer_host: smtp.mailtrap.io
mailer_user: efb44191c15785
mailer_password: 821a734f231165
mailer_port: 2525
mailer_default_from: example@example.com
EMAILS
CHECKING EMAILS
Then the email has been sent:
| currentUser | | | |
| subject | some subject | | |
| html_body | some id | | |
| file | some file | PDF | 9000 |
ALLOWS TO FILTER EMAIL CONTENT
BY MULTIPLE FILEDS
EMAILS
CHECKING EMAILS - FILTERS
▸ currentUser - checks if email was sent to current logged user, requires integration with Kakunin User
Provider
▸ subject - allows to check email subject
▸ html_body - allows to check content of email
▸ file - allows to check attachments, it's type, name and size
ALL FILTERS SUPPORT MATCHERS
REGULAR EXPRESSIONS
REGULAR EXPRESSIONS
REGULAR EXPRESSIONS
CUSTOM REGEX
module.exports = {
matchingStoreId: '(STORE-[0-9]{6}-[0-9]{4})',
emailSubject: '(Join Our Store - STORE-[0-9]{6}-[0-9]{4}‫اﻟﯿﻨﺎ‬ ‫اﻧﻀﻢ‬ -)'
};
USAGE
r:matchingStoreId
CONTENT VALIDATION
CONTENT VALIDATION
CONTENT VALIDATION
FORM VALIDATIONS
Then the error messages should be displayed:
| element | errorMessage |
| nameValidationMsg | This value should not be blank. |
| targetMarketSegmentValidationMsg | This value should not be blank. |
this.nameValidationMsg = $('.name .form__error');
CONTENT VALIDATION
VALIDATE ELEMENT CONTENT
Then there are "equal 1" "todos" elements
uses chai.js expectations
equal X
above X
between X Y
at least X
CONTENT VALIDATION
VALIDATE ELEMENT CONTENT
Then there are "equal 1" "todos" elements
REQUIRES LIST SELECTOR
CONTENT VALIDATION
VALIDATE ELEMENT CONTENT
Then there are "equal 1" "todos" elements
this.todos = $$('ul li');
this.todos = element.all(by.css('ul li'));
CONTENT VALIDATION
VALIDATE ELEMENT CONTENT
Then there is element "myElement" with value "r:notEmpty"
Then there is element "myElement" with value "t:some text"
Then there is element "myElement" with value "f:isClickable"
MATCHERS
CONTENT VALIDATION
ALLOW TO VALIDATE FILED VALUE, BUT ALSO
BEHAVIOUR (FOR EXAMPLE IF ELEMENT IS

CLICKABLE)
CONTENT VALIDATION
CUSTOM MATCHER
const { matchers } = require('kakunin');
class MyMatcher {
isSatisfiedBy(prefix, name) {
return prefix === 'm:' && name === 'pending';
}
match(protractorElement, matcherName) {
return protractorElement.getText().then((value) => value === 'pending');
}
}
matchers.addMatcher(new MyMatcher());
CONTENT VALIDATION
CONTENT VALIDATION
VALIDATE ELEMENT CONTENT - DETAILED CHECK
Then there are "equal 1" following elements for element "todos":
| element | value |
| removeButton | f:isVisible |
REQUIRES LIST SELECTOR
CHILD ELEMENTS MUST BE LOCATORS, NOT ELEMENTS
CONTENT VALIDATION
this.todos = $$('ul li');
Then there are "equal 1" following elements for element "todos":
| element | value |
| removeButton | f:isVisible |
this.removeButton = by.css('.remove');
VALIDATE ELEMENT CONTENT - DETAILED CHECK
FILE DOWNLOAD
CONTENT VALIDATION
CONTENT VALIDATION
FILE DOWNLOAD
Then the file "fileName.extension" should be downloaded
downloaded file name, the same as the one normally have in browser
CONTENT VALIDATION
FILE DOWNLOAD - CLEAR DOWNLOAD DIRECTORY
@downloadClearAfter
@downloadClearBefore
QUESTIONS ?
KAKUNIN WORKSHOPS
THANK YOU

Weitere ähnliche Inhalte

Was ist angesagt?

Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2KZepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Thomas Fuchs
 

Was ist angesagt? (20)

React & redux
React & reduxReact & redux
React & redux
 
Get AngularJS Started!
Get AngularJS Started!Get AngularJS Started!
Get AngularJS Started!
 
React и redux
React и reduxReact и redux
React и redux
 
jQuery in 15 minutes
jQuery in 15 minutesjQuery in 15 minutes
jQuery in 15 minutes
 
Angular Performance: Then, Now and the Future. Todd Motto
Angular Performance: Then, Now and the Future. Todd MottoAngular Performance: Then, Now and the Future. Todd Motto
Angular Performance: Then, Now and the Future. Todd Motto
 
Polymer - pleasant client-side programming with web components
Polymer - pleasant client-side programming with web componentsPolymer - pleasant client-side programming with web components
Polymer - pleasant client-side programming with web components
 
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2KZepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
 
React
React React
React
 
Switch to React.js from AngularJS developer
Switch to React.js from AngularJS developerSwitch to React.js from AngularJS developer
Switch to React.js from AngularJS developer
 
JavaScript Promises
JavaScript PromisesJavaScript Promises
JavaScript Promises
 
Better Testing With PHP Unit
Better Testing With PHP UnitBetter Testing With PHP Unit
Better Testing With PHP Unit
 
Promise pattern
Promise patternPromise pattern
Promise pattern
 
REACT.JS : Rethinking UI Development Using JavaScript
REACT.JS : Rethinking UI Development Using JavaScriptREACT.JS : Rethinking UI Development Using JavaScript
REACT.JS : Rethinking UI Development Using JavaScript
 
React state managmenet with Redux
React state managmenet with ReduxReact state managmenet with Redux
React state managmenet with Redux
 
22 j query1
22 j query122 j query1
22 j query1
 
React JS and Redux
React JS and ReduxReact JS and Redux
React JS and Redux
 
jQuery PPT
jQuery PPTjQuery PPT
jQuery PPT
 
ReactJs presentation
ReactJs presentationReactJs presentation
ReactJs presentation
 
Intro to ReactJS
Intro to ReactJSIntro to ReactJS
Intro to ReactJS
 
Step objects
Step objectsStep objects
Step objects
 

Ähnlich wie Kakunin E2E framework showcase

Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011
Chris Alfano
 
Javascript unit testing, yes we can e big
Javascript unit testing, yes we can   e bigJavascript unit testing, yes we can   e big
Javascript unit testing, yes we can e big
Andy Peterson
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahoda
Droidcon Berlin
 

Ähnlich wie Kakunin E2E framework showcase (20)

Good karma: UX Patterns and Unit Testing in Angular with Karma
Good karma: UX Patterns and Unit Testing in Angular with KarmaGood karma: UX Patterns and Unit Testing in Angular with Karma
Good karma: UX Patterns and Unit Testing in Angular with Karma
 
Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011
 
Web Components Everywhere
Web Components EverywhereWeb Components Everywhere
Web Components Everywhere
 
Clean Javascript
Clean JavascriptClean Javascript
Clean Javascript
 
BDD, ATDD, Page Objects: The Road to Sustainable Web Testing
BDD, ATDD, Page Objects: The Road to Sustainable Web TestingBDD, ATDD, Page Objects: The Road to Sustainable Web Testing
BDD, ATDD, Page Objects: The Road to Sustainable Web Testing
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using Codeception
 
Javascript unit testing, yes we can e big
Javascript unit testing, yes we can   e bigJavascript unit testing, yes we can   e big
Javascript unit testing, yes we can e big
 
Improving android experience for both users and developers
Improving android experience for both users and developersImproving android experience for both users and developers
Improving android experience for both users and developers
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahoda
 
Dan Webb Presentation
Dan Webb PresentationDan Webb Presentation
Dan Webb Presentation
 
How to Mess Up Your Angular UI Components
How to Mess Up Your Angular UI ComponentsHow to Mess Up Your Angular UI Components
How to Mess Up Your Angular UI Components
 
Workshop: Building Vaadin add-ons
Workshop: Building Vaadin add-onsWorkshop: Building Vaadin add-ons
Workshop: Building Vaadin add-ons
 
Connect.js - Exploring React.Native
Connect.js - Exploring React.NativeConnect.js - Exploring React.Native
Connect.js - Exploring React.Native
 
Choosing a Javascript Framework
Choosing a Javascript FrameworkChoosing a Javascript Framework
Choosing a Javascript Framework
 
Testable, Object-Oriented JavaScript
Testable, Object-Oriented JavaScriptTestable, Object-Oriented JavaScript
Testable, Object-Oriented JavaScript
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVC
 
Introducing jQuery
Introducing jQueryIntroducing jQuery
Introducing jQuery
 
jQuery Best Practice
jQuery Best Practice jQuery Best Practice
jQuery Best Practice
 
Three Simple Chords of Alternative PageObjects and Hardcore of LoadableCompon...
Three Simple Chords of Alternative PageObjects and Hardcore of LoadableCompon...Three Simple Chords of Alternative PageObjects and Hardcore of LoadableCompon...
Three Simple Chords of Alternative PageObjects and Hardcore of LoadableCompon...
 
Backbone - TDC 2011 Floripa
Backbone - TDC 2011 FloripaBackbone - TDC 2011 Floripa
Backbone - TDC 2011 Floripa
 

Mehr von The Software House

Mehr von The Software House (20)

Jak kraść miliony, czyli o błędach bezpieczeństwa, które mogą spotkać również...
Jak kraść miliony, czyli o błędach bezpieczeństwa, które mogą spotkać również...Jak kraść miliony, czyli o błędach bezpieczeństwa, które mogą spotkać również...
Jak kraść miliony, czyli o błędach bezpieczeństwa, które mogą spotkać również...
 
Uszanowanko Podsumowanko
Uszanowanko PodsumowankoUszanowanko Podsumowanko
Uszanowanko Podsumowanko
 
Jak efektywnie podejść do certyfikacji w AWS?
Jak efektywnie podejść do certyfikacji w AWS?Jak efektywnie podejść do certyfikacji w AWS?
Jak efektywnie podejść do certyfikacji w AWS?
 
O co chodzi z tą dostępnością cyfrową?
O co chodzi z tą dostępnością cyfrową?O co chodzi z tą dostępnością cyfrową?
O co chodzi z tą dostępnością cyfrową?
 
Chat tekstowy z użyciem Amazon Chime
Chat tekstowy z użyciem Amazon ChimeChat tekstowy z użyciem Amazon Chime
Chat tekstowy z użyciem Amazon Chime
 
Migracje danych serverless
Migracje danych serverlessMigracje danych serverless
Migracje danych serverless
 
Jak nie zwariować z architekturą Serverless?
Jak nie zwariować z architekturą Serverless?Jak nie zwariować z architekturą Serverless?
Jak nie zwariować z architekturą Serverless?
 
Analiza semantyczna artykułów prasowych w 5 sprintów z użyciem AWS
Analiza semantyczna artykułów prasowych w 5 sprintów z użyciem AWSAnaliza semantyczna artykułów prasowych w 5 sprintów z użyciem AWS
Analiza semantyczna artykułów prasowych w 5 sprintów z użyciem AWS
 
Feature flags na ratunek projektu w JavaScript
Feature flags na ratunek projektu w JavaScriptFeature flags na ratunek projektu w JavaScript
Feature flags na ratunek projektu w JavaScript
 
Typowanie nominalne w TypeScript
Typowanie nominalne w TypeScriptTypowanie nominalne w TypeScript
Typowanie nominalne w TypeScript
 
Automatyzacja tworzenia frontendu z wykorzystaniem GraphQL
Automatyzacja tworzenia frontendu z wykorzystaniem GraphQLAutomatyzacja tworzenia frontendu z wykorzystaniem GraphQL
Automatyzacja tworzenia frontendu z wykorzystaniem GraphQL
 
Serverless Compose vs hurtownia danych
Serverless Compose vs hurtownia danychServerless Compose vs hurtownia danych
Serverless Compose vs hurtownia danych
 
Testy API: połączenie z bazą danych czy implementacja w pamięci
Testy API: połączenie z bazą danych czy implementacja w pamięciTesty API: połączenie z bazą danych czy implementacja w pamięci
Testy API: połączenie z bazą danych czy implementacja w pamięci
 
Jak skutecznie read model. Case study
Jak skutecznie read model. Case studyJak skutecznie read model. Case study
Jak skutecznie read model. Case study
 
Firestore czyli ognista baza od giganta z Doliny Krzemowej
Firestore czyli ognista baza od giganta z Doliny KrzemowejFirestore czyli ognista baza od giganta z Doliny Krzemowej
Firestore czyli ognista baza od giganta z Doliny Krzemowej
 
Jak utrzymać stado Lambd w ryzach
Jak utrzymać stado Lambd w ryzachJak utrzymać stado Lambd w ryzach
Jak utrzymać stado Lambd w ryzach
 
Jak poskromić AWS?
Jak poskromić AWS?Jak poskromić AWS?
Jak poskromić AWS?
 
O łączeniu Storyblok i Next.js
O łączeniu Storyblok i Next.jsO łączeniu Storyblok i Next.js
O łączeniu Storyblok i Next.js
 
Amazon Step Functions. Sposób na implementację procesów w chmurze
Amazon Step Functions. Sposób na implementację procesów w chmurzeAmazon Step Functions. Sposób na implementację procesów w chmurze
Amazon Step Functions. Sposób na implementację procesów w chmurze
 
Od Figmy do gotowej aplikacji bez linijki kodu
Od Figmy do gotowej aplikacji bez linijki koduOd Figmy do gotowej aplikacji bez linijki kodu
Od Figmy do gotowej aplikacji bez linijki kodu
 

Kürzlich hochgeladen

AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
VishalKumarJha10
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
mohitmore19
 

Kürzlich hochgeladen (20)

Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
SHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions PresentationSHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions Presentation
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 

Kakunin E2E framework showcase

  • 2. ADAM POLAK PHP DEVELOPER JS DEVELOPER E2E DEVELOPER E2E DEVELOPER JS DEVELOPER TOMASZ GÓRSKI
  • 3. KAKUNIN WORKSHOPS AGENDA ▸ HOW TO INSTALL AND CONFIGURE KAKUNIN? ▸ HOW TO NAVIGATE BETWEEN PAGES AND VALIDATE CURRENT PAGE? ▸ HOW TO INTERACT WITH ELEMENTS AND VALIDATE CONTENT? ▸ HOW TO FILL IN, CHECK OUT ITS VALUES AND VALIDATE FORMS? ▸ HOW TO CHECK EMAILS CONTENT? ▸ HOW TO DEBUG KAKUNIN?
  • 4. KAKUNIN WORKSHOPS ▸ HOW TO EXTEND KAKUNIN WITH CUSTOM STEPS? ▸ HOW TO HANDLE NON-BUILT-IN FORM FIELD TYPES? ▸ HOW TO ADD SCENARIO SPECIFIC HOOKS? ▸ HOW TO CONNECT DIFFERENT MAILING SERVICE? AGENDA
  • 6. WHAT IS KAKUNIN? ▸ PROTRACTOR EXTENSION ▸ GHERKIN AS A PROGRAMMING LANGUAGE ▸ BUILT-IN STEPS TO SOLVE MOST COMMON CASES ▸ EASLY EXTENDABLE ▸ HANDLES ANGULAR AND NON-ANGULAR APPS OUT OF THE BOX KAKUNIN
  • 7. WHAT ARE WE GOING TO TEST? KAKUNIN WORKSHOPS
  • 8. INSTALATION HOW TO INSTALL? { "name": "workshop", "version": "0.0.1", "description": "", "main": "index.js", "scripts": { "test": "echo "Error: no test specified" && exit 1" }, "author": "", "license": "ISC" } cd kakunin-workshop mkdir kakunin-workshop npm init
  • 9. INSTALATION HOW TO INSTALL? npm install webdriver-manager
 npm install protractor
 npm install kakunin { ... "scripts": { ... "kakunin": "NODE_ENV=prod kakunin" }, ... "devDependencies": { ...
 "webdriver-manager": "12.0.6", "protractor": "5.1.2", "kakunin": "1.0.1" } }
  • 10. INSTALATION HOW TO INSTALL? npm run kakunin init cd step_definitions
 ln -s ../node_modules/kakunin/dist/step_definitions/elements.js kakunin-elements.js ln -s ../node_modules/kakunin/dist/step_definitions/debug.js kakunin-debug.js ln -s ../node_modules/kakunin/dist/step_definitions/file.js kakunin-file.js ln -s ../node_modules/kakunin/dist/step_definitions/form.js kakunin-form.js ln -s ../node_modules/kakunin/dist/step_definitions/email.js kakunin-email.js ln -s ../node_modules/kakunin/dist/step_definitions/generators.js kakunin-generators.js ln -s ../node_modules/kakunin/dist/step_definitions/navigation.js kakunin-navigation.js
  • 11. INSTALATION HOW TO INSTALL? npm run kakunin Scenario: If you can see this in console then hook is working properly. ✔ When I visit the "page" page ✔ And I generate random "name" as "myName" ✔ Then my matcher "e:name" matches "v:myName" ✔ And my matcher "e:name" matches "Bob" 1 scenario (1 passed) 4 steps (4 passed) 0m00.757s
  • 12. INSTALATION HOW TO RUN A SINGLE SCENARIO? npm run kakunin -- --tags @someTag npm run kakunin -- --tags="@someTag and @otherTag" npm run kakunin -- --tags="@someTag or @otherTag" npm run kakunin -- --tags="not @someTag"
  • 14. NAVIGATE BETWEEN PAGES PAGE OBJECT const { BasePage } = require('kakunin'); class MainPage extends BasePage { constructor() { super(); this.url = '/'; } } module.exports = new MainPage();
  • 15. NAVIGATE BETWEEN PAGES SCENARIO - NAVIGATING Feature: Load main page Scenario: Load main page as homepage Given/When I visit the "main" page The name of a page object file. For this case there has to be a file "main.js" in pages directory.
  • 16. NAVIGATE BETWEEN PAGES SCENARIO - CHECKING OUT ON WHAT PAGE WE ARE Then the "main" page is displayed The name of a page object file. For this case there has to be a file "main.js" in pages directory.
  • 17. NAVIGATE BETWEEN PAGES SCENARIO - DEBUGGING Give/When/Then I wait for "20" seconds Give/When/Then I pause
  • 18. NAVIGATE BETWEEN PAGES WHAT ABOUT URL WITH PARAMETERS ? /suppliers/some-supplier-id/clients/some-client-id /suppliers/:supplierId/clients/:clientId ... this.url = '/suppliers/:supplierId/clients/:clientId'; ...
  • 19. NAVIGATE BETWEEN PAGES PAGE CONTEXT Then the "main" page is displayed EVERY BUILT-IN STEP (EXCEPT NAVIGATION ONES) WILL HAVE AN ACCESS TO MAIN PAGE OBJECT.
  • 21. INTERACTING WITH ELEMENTS Then the "showActive" element is visible The name of a selector from current page object file. ELEMENT VISIBILITY
  • 22. INTERACTING WITH ELEMENTS SELECTORS ▸ defines access to element ▸ support for protractor locators
 http://www.protractortest.org/#/api? view=ProtractorBy ▸ support for angular only attributes
  • 23. INTERACTING WITH ELEMENTS SELECTORS ▸ id attribute, custom attribute, custom class, unique class - GOOD ▸ for angular app: ng-model, ng-repeat - GOOD ▸ html tag - BAD ▸ angular validation classes (ng-valid, ng-pristine etc) - VERY BAD
  • 24. INTERACTING WITH ELEMENTS SELECTORS this.mySelectorName = $('.css-selector'); this.mySelectorName = $('html-tag'); this.mySelectorName = $('html-tag.css-selector'); this.mySelectorName = element(by.repeater('project in projects'));
  • 25. INTERACTING WITH ELEMENTS Then the "showActive" element is visible ELEMENT VISIBILITY - PROBLEM THE ELEMENT MUST BE VISIBLE RIGHT AWAY. IT DOES NOT WAIT FOR ELEMENT TO BE VISIBLE.
  • 26. INTERACTING WITH ELEMENTS When/Given/Then I wait for "visibilityOf" of the "showActive" element ELEMENT VISIBILITY - SOLUTION uses protractors expected conditions internally, for example visibilityOf invisibilityOf
  • 27. INTERACTING WITH ELEMENTS ELEMENT VISIBILITY - WHAT ELSE? When/Given/Then the "showCompleted" element is present When/Given/Then the "showCompleted" element is not visible When/Given/Then the "showCompleted" element is not present
  • 28. INTERACTING WITH ELEMENTS When I fill the "myForm" form with: | fieldSelector | value to be used | Form selector Input selector this.myForm = $('.add-todo'); this.fieldSelector = $('.add-todo input[name="add-todo"]'); FILLING UP FORM
  • 29. INTERACTING WITH ELEMENTS Then the "myForm" form is filled with: | fieldSelector | value to be used | Form selector Input selector CHECKING OUT FORM VALUE
  • 30. INTERACTING WITH ELEMENTS WHAT ABOUT DIFFERENT FIELD TYPES? ▸ supports all of the basic html field types (radio, checkbox, textarea, select, file, text) ▸ allows to add custom made handlers for field types
  • 31. INTERACTING WITH ELEMENTS HOW ABOUT SUBMITTING ? When I click the "addTodoButton" element The name of a selector from current page object file.
  • 33. CUSTOM STEPS OUR STEP Given I am logged in as an "submitter" User role
  • 34. CUSTOM STEPS CUCUMBER 2.0 - STEP DEFINITION const { defineSupportCode } = require('kakunin'); defineSupportCode(({ Given }) => { Given(/^I am logged in as an "([^"]*)"$/, function (user) { return Promise.resolve(); }); });
  • 35. CUSTOM STEPS ACCESS PAGE FROM CODE const myPage = browser.page.myPage;
  • 36. CUSTOM STEPS BASE PAGE METHODS visit() click(elementSelectorName) isDisabled(elementSelectorName) isPresent(elementSelectorName) isVisible(elementSelectorName) isOn()
  • 37. CUSTOM STEPS BASE PAGE METHODS getNumberOfElements(elementSelectorName) scrollIntoElement(elementSelectorName, optionalIndexForArrayElement)
  • 38. CUSTOM STEPS BASE PAGE METHODS fillForm(formData) [ [ 'fieldSelector', 'fieldValue' ] ] checkForm(formData) [ [ 'fieldSelector', 'fieldValue' ] ]
  • 39. CUSTOM STEPS BASE PAGE METHODS fillField(fieldSelector, fiedlValue) checkField(fieldSelector, fiedlValue) EVERY METHOD RETURNS A PROMISE
  • 40. CUSTOM STEPS USER PROVIDER this.userProvider.getUser(userName); accounts: { userName: { accounts: [ { email: 'some@email.com', password: 'somePassword' } ] }
 }
  • 41. CUSTOM STEPS USER PROVIDER this.currentUser = { account: { email: 'some@email.com', password: 'somePassword' }, type: "userName" }
  • 43. HOOKS HOOK DEFINITION const { defineSupportCode } = require('kakunin'); defineSupportCode(({ After }) => { After(() => {
 return Promise.resolve();
 }); }); defineSupportCode(({ After }) => { After('@someTag', () => {
 return Promise.resolve();
 }); });
  • 44. HOOKS HOOK DEFINITION - EXECUTE REMOTE JS CODE protractor.browser.executeScript('your js code to be run inside a browser');
  • 45. HOOKS HOOK DEFINITION - CLEAR COOKIES protractor.browser.manage().deletAllCookies();
  • 48. CUSTOM HANDLERS INTERFACE isSatisfiedBy(element, elementName) { return Promise.resolve(); } handleFill(page, elementName, desiredValue) { return Promise.resolve(); } handleCheck(page, elementName, desiredValue) { return Promise.resolve(); } getPriority() { return 1000; }
  • 49. CUSTOM HANDLERS HANDLER SERVICE - ADDING NEW HANDLER const { handlers } = require('kakunin'); class MyHandler {} handler.addHandler(new MyHandler());
  • 50. CUSTOM HANDLERS CUSTOM SELECT HTML <div class="form__field serviceMarket form__field--danger"> <label class="form__label form__label--required">Service Market</label> <div class="Select Select--single is-clearable is-focused is-open"> <div class="Select-control"> </div> <div class="Select-menu-outer"> <div role="listbox" class="Select-menu"> <div style="overflow: visible; width: 0px;"> <div aria-label="grid" class="ReactVirtualized__Grid ReactVirtualized__List VirtualSelectGrid"> <div class="ReactVirtualized__Grid__innerScrollContainer"> <div class="select__option" data-e2e="/app_e2e.php/service_markets/ 80a06089-2f94-4992-8f7c-1d30fc7b8a3e">SME Services</div> </div> </div> </div> </div> </div> </div> </div>
  • 51. CUSTOM HANDLERS CUSTOM SELECT HTML - SELECTED OPTION <div class="form__field serviceMarket"> <label class="form__label form__label--required">Service Market</label> <div class="Select Select--single is-clearable has-value"> <input type="hidden" name="serviceMarket" value="/app_e2e.php/service_markets/ 80a06089-2f94-4992-8f7c-1d30fc7b8a3e"> </div> </div>
  • 53. TRANSFORMERS A WAY TO GENERATE OR TRANSFORM VALUES FROM
 HUMAN READABLE VERSION TO APP USABLE.
  • 55. TRANSFORMERS When I fill the "myForm" form with: | projectUrl | http://some-url.com | | projectType | 1234 | WITHOUT TRANSFORMERS When I fill the "myForm" form with: | projectUrl | g:projectUrl | | projectType | d:projectTypes:website | WITH TRANSFORMERS
  • 56. TRANSFORMERS GENERATORS const { generators } = require('kakunin'); class ProjectUrlGenerator{ isSatisfiedBy(name) { return this.name === 'projectUrl'; } generate(params) { return Promise.resolve('http://some-url.pl'); } } generators.addGenerator(new ProjectUrlGenerator());
  • 57. TRANSFORMERS DICTIONARIES const { dictionaries } = require('kakunin'); class ProjectTypesDictionary{ constructor() { this.values = { 'myServiceMarket':'/service_markets/80a06089-2f94-4992-8f7c-1d30fc7b8a3e' }; this.name = 'projectTypes'; } isSatisfiedBy(name) { return this.name === name; } getMappedValue(key) { return this.values[key]; } } dictionaries.addDictionary(new ProjectTypesDictionary());
  • 59. EMAILS CONFIGURATION email: { type: 'mailtrap', config: { apiKey: '81279e9fb9351ebdf7aefef89e6a5701', inboxId: '203459', url: 'https://mailtrap.io/api/v1' } }, clearEmailInboxBeforeTests: true mailer_host: smtp.mailtrap.io mailer_user: efb44191c15785 mailer_password: 821a734f231165 mailer_port: 2525 mailer_default_from: example@example.com
  • 60. EMAILS CHECKING EMAILS Then the email has been sent: | currentUser | | | | | subject | some subject | | | | html_body | some id | | | | file | some file | PDF | 9000 | ALLOWS TO FILTER EMAIL CONTENT BY MULTIPLE FILEDS
  • 61. EMAILS CHECKING EMAILS - FILTERS ▸ currentUser - checks if email was sent to current logged user, requires integration with Kakunin User Provider ▸ subject - allows to check email subject ▸ html_body - allows to check content of email ▸ file - allows to check attachments, it's type, name and size ALL FILTERS SUPPORT MATCHERS
  • 63. REGULAR EXPRESSIONS CUSTOM REGEX module.exports = { matchingStoreId: '(STORE-[0-9]{6}-[0-9]{4})', emailSubject: '(Join Our Store - STORE-[0-9]{6}-[0-9]{4}‫اﻟﯿﻨﺎ‬ ‫اﻧﻀﻢ‬ -)' }; USAGE r:matchingStoreId
  • 65. CONTENT VALIDATION FORM VALIDATIONS Then the error messages should be displayed: | element | errorMessage | | nameValidationMsg | This value should not be blank. | | targetMarketSegmentValidationMsg | This value should not be blank. | this.nameValidationMsg = $('.name .form__error');
  • 66. CONTENT VALIDATION VALIDATE ELEMENT CONTENT Then there are "equal 1" "todos" elements uses chai.js expectations equal X above X between X Y at least X
  • 67. CONTENT VALIDATION VALIDATE ELEMENT CONTENT Then there are "equal 1" "todos" elements REQUIRES LIST SELECTOR
  • 68. CONTENT VALIDATION VALIDATE ELEMENT CONTENT Then there are "equal 1" "todos" elements this.todos = $$('ul li'); this.todos = element.all(by.css('ul li'));
  • 69. CONTENT VALIDATION VALIDATE ELEMENT CONTENT Then there is element "myElement" with value "r:notEmpty" Then there is element "myElement" with value "t:some text" Then there is element "myElement" with value "f:isClickable"
  • 71. ALLOW TO VALIDATE FILED VALUE, BUT ALSO BEHAVIOUR (FOR EXAMPLE IF ELEMENT IS
 CLICKABLE) CONTENT VALIDATION
  • 72. CUSTOM MATCHER const { matchers } = require('kakunin'); class MyMatcher { isSatisfiedBy(prefix, name) { return prefix === 'm:' && name === 'pending'; } match(protractorElement, matcherName) { return protractorElement.getText().then((value) => value === 'pending'); } } matchers.addMatcher(new MyMatcher()); CONTENT VALIDATION
  • 73. CONTENT VALIDATION VALIDATE ELEMENT CONTENT - DETAILED CHECK Then there are "equal 1" following elements for element "todos": | element | value | | removeButton | f:isVisible | REQUIRES LIST SELECTOR CHILD ELEMENTS MUST BE LOCATORS, NOT ELEMENTS
  • 74. CONTENT VALIDATION this.todos = $$('ul li'); Then there are "equal 1" following elements for element "todos": | element | value | | removeButton | f:isVisible | this.removeButton = by.css('.remove'); VALIDATE ELEMENT CONTENT - DETAILED CHECK
  • 76. CONTENT VALIDATION FILE DOWNLOAD Then the file "fileName.extension" should be downloaded downloaded file name, the same as the one normally have in browser
  • 77. CONTENT VALIDATION FILE DOWNLOAD - CLEAR DOWNLOAD DIRECTORY @downloadClearAfter @downloadClearBefore