SlideShare a Scribd company logo
Nightwatch at Tilt
San Francisco Selenium Meetup
March 4th, 2015
About Me
• NJ -> UIUC -> Penn State -> Blacksburg VA -> SF Bay Area
• Grad School -> WebDev -> DevOps Lead -> Frontend Lead
• Java -> Python -> JavaScript
• @tildedave
• Blog, etc: tildedave.com
San Francisco Selenium Meetup March 4th 2014
Tilt
Make Amazing Things Happen
San Francisco Selenium Meetup March 4th 2014
Tilt is a social crowd-funding
company
San Francisco Selenium Meetup March 4th 2014
San Francisco Selenium Meetup March 4th 2014
“Move Fast and Break
Things”
It turns out that this statement is a lie
San Francisco Selenium Meetup March 4th 2014
Golden Features
• Login
• Signup
• Contribution Flow
• Commenting
• Admin Payouts
• … really no user flow can ever break acceptably
San Francisco Selenium Meetup March 4th 2014
Selenium at Tilt
San Francisco Selenium Meetup March 4th 2014
History of Selenium at Tilt
• CI/CD environment - push code to production daily
• No dedicated QA resources as part of the
development team
• Must not break core flows
San Francisco Selenium Meetup March 4th 2014
History of Selenium at Tilt
• Pre-History: PhantomJS/PhantomProxy - no visibility
on failures
• February 2013 - Introduce Selenium for functional
testing (2.31.0)
• June 2014 - Selenium tests vs staging/production as a
‘health check’ of deployed code (2.42.2)
San Francisco Selenium Meetup March 4th 2014
Ancient Code: Phantom JS
!
promiseIt('can contribute to regular campaign', function(p) {!
return p!
.withPrimedCampaign()!
.thenOpenCampaignPage()!
.thenLightboxClick('.campaign-tilt-info .btn')!
.thenType('#amount_lightbox', '2.00')!
.thenClickAndWaitForDocumentReady('#contribute-continue')!
.thenVerifyElementContents('#display-total', '2.05')!
.thenFillCCForm()!
.thenClickAndWaitAndFailIfLightboxCloses('#confirm-btn')!
.thenWait(1000)!
.thenVerifyElementVisible('#just_contributed')!
.thenCancelCampaign();!
});!
!
San Francisco Selenium Meetup March 4th 2014
Today: Nightwatch Tests
'Can contribute as admin': function(client) {!
var selectors = client.page.campaign().selectors;!
client.page.homepage().load()!
.createFBUserAndLogIn()!
.createCampaignAPI({}, function(campaign) {!
return client.page.campaign().load(campaign.title);!
})!
.page.campaign().clickContribute()!
.page.contributionFlow().enterContributionAmount('2')!
.page.contributionFlow().checkOut()!
.page.contributionFlow().skipInviteAndShare()!
// admins don't get asked to comment!
.verify.elementNotPresent(selectors.lightboxTitle)!
.end();!
}!
San Francisco Selenium Meetup March 4th 2014
Nightwatch at Tilt
• September 2014
• Selenium suite run on every branch before merge
• Lots of flapping tests - developers often rerun tests
until green
• Test suite expansion seems like a nightmare - lots of
selectors in tests, copy/pasted setup, etc
• October 2014 - We start investigating better solutions
San Francisco Selenium Meetup March 4th 2014
Nightwatch.js
San Francisco Selenium Meetup March 4th 2014
Nightwatch
• http://nightwatchjs.org/
• Better interface to selenium-webdriver
• Library provides Custom Commands, Page Objects,
and Assertions
• It’s in JavaScript!
San Francisco Selenium Meetup March 4th 2014
Why Nightwatch for Tilt?
• It’s in JavaScript
• Using Ruby just for tests is a hard sell
• Easily use npm modules as part of your tests
• Builds in important concepts that Tilt had rolled itself
(custom commands) or should have (page objects)
• Old suite had too much technical debt to be saved
San Francisco Selenium Meetup March 4th 2014
Tiltcabulary
• Users - users of the site
• Campaigns - crowdfunding campaigns
San Francisco Selenium Meetup March 4th 2014
Basic Nightwatch Test for
tilt.com
San Francisco Selenium Meetup March 4th 2014
Basic Nightwatch Test for
tilt.com
module.exports = {!
'Tilt.com': function(client) {!
var title = 'Collect money from your group';!
client!
.url('https://www.tilt.com')!
.waitForElementVisible('.hero-title', 1000)!
.verify.containsText('.hero-title',!
title)!
.end();!
}!
};!
San Francisco Selenium Meetup March 4th 2014
Basic Nightwatch Test for
tilt.com
module.exports = {!
'Tilt.com': function(client) {!
var title = 'Collect money from your group';!
client!
.url('https://www.tilt.com')!
.waitForElementVisible('.hero-title', 1000)!
.verify.containsText('.hero-title',!
title)!
.end();!
}!
};!
San Francisco Selenium Meetup March 4th 2014
Arrange
Basic Nightwatch Test for
tilt.com
module.exports = {!
'Tilt.com': function(client) {!
var title = 'Collect money from your group';!
client!
.url('https://www.tilt.com')!
.waitForElementVisible('.hero-title', 1000)!
.verify.containsText('.hero-title',!
title)!
.end();!
}!
};!
San Francisco Selenium Meetup March 4th 2014
Assert
Basic Nightwatch Test for
tilt.com
• We have a video on our homepage. Probably it
shouldn’t break.















San Francisco Selenium Meetup March 4th 2014
Basic Nightwatch Test for
tilt.com
San Francisco Selenium Meetup March 4th 2014
Basic Nightwatch Test for
tilt.com
module.exports = {!
'Tilt.com Video': function(client) {!
client!
.url('https://www.tilt.com')!
.waitForElementVisible(‘.video-link', 1000)!
.pause(3000) // vidyard JS must have loaded!
.click('.video-link')!
.waitForElementVisible('.vidyard_tclose', 3000)!
.click('.vidyard_tclose')!
.end();!
}!
};!
San Francisco Selenium Meetup March 4th 2014
Basic Nightwatch Test for
tilt.com
module.exports = {!
'Tilt.com Video': function(client) {!
client!
.url('https://www.tilt.com')!
.waitForElementVisible(‘.video-link', 1000)!
.pause(3000) // vidyard JS must have loaded!
.click('.video-link')!
.waitForElementVisible('.vidyard_tclose', 3000)!
.click('.vidyard_tclose')!
.end();!
}!
};!
San Francisco Selenium Meetup March 4th 2014
Arrange
Basic Nightwatch Test for
tilt.com
module.exports = {!
'Tilt.com Video': function(client) {!
client!
.url('https://www.tilt.com')!
.waitForElementVisible(‘.video-link', 1000)!
.pause(3000) // vidyard JS must have loaded!
.click('.video-link')!
.waitForElementVisible('.vidyard_tclose', 3000)!
.click('.vidyard_tclose')!
.end();!
}!
};!
San Francisco Selenium Meetup March 4th 2014
Act
Basic Nightwatch Test for
tilt.com
module.exports = {!
'Tilt.com Video': function(client) {!
client!
.url('https://www.tilt.com')!
.waitForElementVisible(‘.video-link', 1000)!
.pause(3000) // vidyard JS must have loaded!
.click('.video-link')!
.waitForElementVisible('.vidyard_tclose', 3000)!
.click('.vidyard_tclose')!
.end();!
}!
};!
San Francisco Selenium Meetup March 4th 2014
Assert
Basic Homepage Page
Object
module.exports = function (client) {!
var selectors = {!
title: '.hero-title',!
video: '.vidyard_tbox',!
videoLink: '.video-link',!
videoClose: '.vidyard_tclose'!
};!
this.selectors = selectors;!
!
this.openVideo = function() {!
return client!
.waitForElementVisible(selectors.videoLink, 1000)!
.click(selectors.videoLink)!
.waitForElementVisible(selectors.videoClose, 5000);!
};!
!
this.closeVideo = function() {!
return client!
.waitForElementVisible(selectors.videoClose, 1000)!
.click(selectors.videoClose)!
.waitForElementNotVisible(selectors.videoClose, 5000);!
};!
};!
San Francisco Selenium Meetup March 4th 2014
Basic Homepage Page
Object
module.exports = function (client) {!
var selectors = {!
title: '.hero-title',!
video: '.vidyard_tbox',!
videoLink: '.video-link',!
videoClose: '.vidyard_tclose'!
};!
this.selectors = selectors;!
!
this.openVideo = function() {!
return client!
.waitForElementVisible(selectors.videoLink, 1000)!
.click(selectors.videoLink)!
.waitForElementVisible(selectors.videoClose, 5000);!
};!
!
this.closeVideo = function() {!
return client!
.waitForElementVisible(selectors.videoClose, 1000)!
.click(selectors.videoClose)!
.waitForElementNotVisible(selectors.videoClose, 5000);!
};!
};!
San Francisco Selenium Meetup March 4th 2014
Unify DOM selectors

as variables
Basic Homepage Page
Object
module.exports = function (client) {!
var selectors = {!
title: '.hero-title',!
video: '.vidyard_tbox',!
videoLink: '.video-link',!
videoClose: '.vidyard_tclose'!
};!
this.selectors = selectors;!
!
this.openVideo = function() {!
return client!
.waitForElementVisible(selectors.videoLink, 1000)!
.click(selectors.videoLink)!
.waitForElementVisible(selectors.videoClose, 5000);!
};!
!
this.closeVideo = function() {!
return client!
.waitForElementVisible(selectors.videoClose, 1000)!
.click(selectors.videoClose)!
.waitForElementNotVisible(selectors.videoClose, 5000);!
};!
};!
San Francisco Selenium Meetup March 4th 2014
Utility Methods for
Tests
Basic Page Objects
module.exports = {!
!
'Tilt.com Video': function(client) {!
var title = 'Collect money from your group';!
client!
.url(‘https://www.tilt.com')!
.page.homepage().openVideo()!
.verify.elementPresent(!
client.page.homepage().selectors.video!
)!
.page.homepage().closeVideo()!
.end();!
}!
!
};!
San Francisco Selenium Meetup March 4th 2014
Basic Page Objects
module.exports = {!
!
'Tilt.com Video': function(client) {!
var title = 'Collect money from your group';!
client!
.url(‘https://www.tilt.com')!
.page.homepage().openVideo()!
.verify.elementPresent(!
client.page.homepage().selectors.video!
)!
.page.homepage().closeVideo()!
.end();!
}!
!
};!
San Francisco Selenium Meetup March 4th 2014
No selectors in tests
Basic Page Objects
module.exports = {!
!
'Tilt.com Video': function(client) {!
var title = 'Collect money from your group';!
client!
.url(‘https://www.tilt.com')!
.page.homepage().openVideo()!
.verify.elementPresent(!
client.page.homepage().selectors.video!
)!
.page.homepage().closeVideo()!
.end();!
}!
!
};!
San Francisco Selenium Meetup March 4th 2014
Waits common
to the page now inside
the page object
Why Nightwatch?
• Three features you would otherwise build yourself
• Page Objects
• Custom Commands
• Custom Assertions
San Francisco Selenium Meetup March 4th 2014
Page Objects
• Basic design pattern - abstract page behavior out of
selectors
• Add in common functions for interacting with page
• In our repo: abstract different desktop/mobile behavior
into the page object
San Francisco Selenium Meetup March 4th 2014
Page Object Example:
“Contribution Flow”
this.enterContributionAmount = function(amount) {!
var sels = (client.globals.isDesktop) ?!
selectors.desktop : selectors.mobile;!
return client!
.waitForElementVisible(sels.contributeAmountField,!
client.globals.timeout)!
.setValue(sels.contributeAmountField, amount)!
.pause(500)!
.click(seles.contributeStep1Submit)!
.waitForElementNotVisible(!
sels.contributeStep1Submit,!
client.globals.timeout!
);!
};!
San Francisco Selenium Meetup March 4th 2014
Page Objects: Desktop vs
Mobile
San Francisco Selenium Meetup March 4th 2014
Page Objects: Desktop vs
Mobile
San Francisco Selenium Meetup March 4th 2014
Expiration is

two fields
Expiration is 

one field
Page Objects: Desktop vs
Mobile
this.enterCreditCard = function(cardNumber, expirationMonth,!
expirationYear, cvc, zip) {!
var platformSelectors = (client.globals.isDesktop) ?!
selectors.desktop :!
selectors.mobile;!
var d = client!
.waitForElementVisible(platformSelectors.cardNumber,!
client.globals.timeout)!
.setValue(platformSelectors.cardNumber,!
[cardNumber, client.Keys.TAB]);!
if (client.globals.isDesktop) {!
d = d.setValue(platformSelectors.expiration,!
[expirationMonth + '/' + expirationYear,!
client.Keys.TAB]);!
} else {!
d = d!
.setValue(platformSelectors.expirationMonth, [expirationMonth,!
client.Keys.TAB])!
.setValue(platformSelectors.expirationYear, [expirationYear,!
client.Keys.TAB]);!
}!
return d!
.setValue(platformSelectors.cvc, [cvc, client.Keys.TAB])!
.setValue(platformSelectors.zip, [zip, client.Keys.TAB]);!
}!
San Francisco Selenium Meetup March 4th 2014
Custom Commands
• Build business-specific language for your tests
• Example commands from our repository:
• createEmailUser
• createEmailUserAndLogIn
• createFacebookTestUser
• setCountry
San Francisco Selenium Meetup March 4th 2014
Custom Assertions
• Add specific assertions to your tests
• We don’t use these as much - examples from our repo:
• isLoggedIn
• linkMatches(text, href)
• lightboxHasHeader
San Francisco Selenium Meetup March 4th 2014
Test Suite Benefits
San Francisco Selenium Meetup March 4th 2014
Bootstrapping JavaScript
• Tilt runs on a hybrid stack
• Old code uses jQuery/jQuery UI for frontend widgets
• New code uses React
• Server-side rendering with a node.js service
San Francisco Selenium Meetup March 4th 2014
Server-side Rendering
Challenges
• Elements in the DOM but not functional
• Elements visible but not functional
San Francisco Selenium Meetup March 4th 2014
Opening the User Menu
San Francisco Selenium Meetup March 4th 2014
Opening the User Menu
this.openUserMenu = function(callback) {!
return client!
.waitForElementVisible(!
this.selectors.menuToggle,!
client.globals.timeout!
)!
// completely arbitrary wait time so that menu JS !
// initializes!
.pause(5000)!
.click(this.selectors.menuToggle)!
.waitForElementVisible('.user-menu', 1000, callback);!
};!
San Francisco Selenium Meetup March 4th 2014
Opening the User Menu
this.openUserMenu = function(callback) {!
return client!
.waitForElementVisible(!
this.selectors.menuToggle,!
client.globals.timeout!
)!
// completely arbitrary wait time so that menu JS !
// initializes!
.pause(5000)!
.click(this.selectors.menuToggle)!
.waitForElementVisible('.user-menu', 1000, callback);!
};!
San Francisco Selenium Meetup March 4th 2014
JavaScript must have
initialized before menu is
functional!
Old Code
window.rewireReact = function() {!
$('[data-mount-as]').each(function() {!
var $this = $(this),!
name = $this.attr('data-mount-as'),!
props = JSON.parse($this.attr('data-props'));!
!
$this.removeAttr('data-mount-as');!
!
// This causes event handlers on the component !
// to become functional!
var component = ReactComponents[name];!
React.render(React.createElement(component, props),!
$this.get(0));!
});!
};!
!
$(document).ready(window.rewireReact);
San Francisco Selenium Meetup March 4th 2014
Old Code
window.rewireReact = function() {!
$('[data-mount-as]').each(function() {!
var $this = $(this),!
name = $this.attr('data-mount-as'),!
props = JSON.parse($this.attr('data-props'));!
!
$this.removeAttr('data-mount-as');!
!
// This causes event handlers on the component !
// to become functional!
var component = ReactComponents[name];!
React.render(React.createElement(component, props),!
$this.get(0));!
});!
};!
!
$(document).ready(window.rewireReact);
Menus only functional
after document ready!
San Francisco Selenium Meetup March 4th 2014
New Code
<!-- Tilt JavaScript bundle -->!
<script src="https://d25y59nqso5bzg.cloudfront.net/built/home-
ce348751.js"></script>!
<!-- all JS is loaded, make the page functional -->!
<script type=“text/javascript”>window.rewireReact();</script>!
San Francisco Selenium Meetup March 4th 2014
New Code
<!-- Tilt JavaScript bundle -->!
<script src="https://d25y59nqso5bzg.cloudfront.net/built/home-
ce348751.js"></script>!
<!-- all JS is loaded, make the page functional -->!
<script type=“text/javascript”>window.rewireReact();</script>!
No more sticky menus!
San Francisco Selenium Meetup March 4th 2014
Test Suite Suggestions
in case you are green-fielding a new test suite
San Francisco Selenium Meetup March 4th 2014
Develop and run tests against
an integration environment
Staging, production, etc - not someone’s local box
San Francisco Selenium Meetup March 4th 2014
Run Tests Constantly
San Francisco Selenium Meetup March 4th 2014
Run Tests Constantly
• We run our tests every 10 minutes against staging
• When you add a wait time to a test you have asserted
that your system always responds in that amount of
time
• See how tests behave in an integration environment
and adjust
San Francisco Selenium Meetup March 4th 2014
Happy Path Tests First
Sad path tests … eventually
San Francisco Selenium Meetup March 4th 2014
Single Responsibility Page
Objects
San Francisco Selenium Meetup March 4th 2014
Page Objects…
• Don’t do test setup
• they don’t make users
• they don’t make campaigns
• Don’t orchestrate complex flows between pages
• Do one thing and one thing only
• (yes this puts more verbosity into your tests)
San Francisco Selenium Meetup March 4th 2014
Problems We’ve Had With
Nightwatch
your mileage may vary!
San Francisco Selenium Meetup March 4th 2014
Hard to run an individual test
Something like mocha —grep would be really great

(currently I just comment out tests)
San Francisco Selenium Meetup March 4th 2014
No Page Object
Documentation Yet
We had to dig through the repo to really understand how to use these
San Francisco Selenium Meetup March 4th 2014
Nondeterminstic Behavior
Page objects sometimes inherit a stale selenium session, repeating “stale element exception”
Use —verbose to see what’s happening if you are really stumped
San Francisco Selenium Meetup March 4th 2014
waitForElementVisible
failures
When running an individual test file, a waitForElementVisible failure causes all
the rest of the tests to be skipped
San Francisco Selenium Meetup March 4th 2014
Nightwatch Pull Requests I
Really Want Merged
• Distinguish between test failures and selenium errors
when taking screenshots: https://github.com/
beatfactor/nightwatch/pull/316
• Run individual test files in parallel with test workers
https://github.com/beatfactor/nightwatch/pull/317
San Francisco Selenium Meetup March 4th 2014
Next Steps for Nightwatch at
Tilt
• Replicate full functionality of old suite
• Cross-browser testing with Saucelabs
• Shard test suite (currently 2 jobs) into specific suites:
• Selenium-Nightwatch-Contribution, Selenium-
Nightwatch-Login, etc.
San Francisco Selenium Meetup March 4th 2014
Thank You!
• Questions?
San Francisco Selenium Meetup March 4th 2014

More Related Content

What's hot

ForwardJS 2017 - Fullstack end-to-end Test Automation with node.js
ForwardJS 2017 -  Fullstack end-to-end Test Automation with node.jsForwardJS 2017 -  Fullstack end-to-end Test Automation with node.js
ForwardJS 2017 - Fullstack end-to-end Test Automation with node.js
Mek Srunyu Stittri
 
Testing nightwatch, by David Torroija
Testing nightwatch, by David TorroijaTesting nightwatch, by David Torroija
Testing nightwatch, by David Torroija
David Torroija
 
Night Watch with QA
Night Watch with QANight Watch with QA
Night Watch with QA
Carsten Sandtner
 
Protractor Tutorial Quality in Agile 2015
Protractor Tutorial Quality in Agile 2015Protractor Tutorial Quality in Agile 2015
Protractor Tutorial Quality in Agile 2015
Andrew Eisenberg
 
Automated Web Testing using JavaScript
Automated Web Testing using JavaScriptAutomated Web Testing using JavaScript
Automated Web Testing using JavaScript
Simon Guest
 
Front-end Automated Testing
Front-end Automated TestingFront-end Automated Testing
Front-end Automated Testing
Ruben Teijeiro
 
Carmen Popoviciu - Protractor styleguide | Codemotion Milan 2015
Carmen Popoviciu - Protractor styleguide | Codemotion Milan 2015Carmen Popoviciu - Protractor styleguide | Codemotion Milan 2015
Carmen Popoviciu - Protractor styleguide | Codemotion Milan 2015
Codemotion
 
Testing frontends with nightwatch & saucelabs
Testing frontends with nightwatch & saucelabsTesting frontends with nightwatch & saucelabs
Testing frontends with nightwatch & saucelabs
Tudor Barbu
 
Unit-testing and E2E testing in JS
Unit-testing and E2E testing in JSUnit-testing and E2E testing in JS
Unit-testing and E2E testing in JS
Michael Haberman
 
Real World Selenium Testing
Real World Selenium TestingReal World Selenium Testing
Real World Selenium Testing
Mary Jo Sminkey
 
AngularJS and Protractor
AngularJS and ProtractorAngularJS and Protractor
AngularJS and Protractor
Filipe Falcão
 
Webdriver cheatsheets summary
Webdriver cheatsheets summaryWebdriver cheatsheets summary
Webdriver cheatsheets summary
Alan Richardson
 
Automated Smoke Tests with Protractor
Automated Smoke Tests with ProtractorAutomated Smoke Tests with Protractor
Automated Smoke Tests with Protractor
🌱 Dale Spoonemore
 
JavaScript Testing VIA Selenium
JavaScript Testing VIA SeleniumJavaScript Testing VIA Selenium
JavaScript Testing VIA Selenium
Adam Christian
 
Automate testing with behat, selenium, phantom js and nightwatch.js (5)
Automate testing with behat, selenium, phantom js and nightwatch.js (5)Automate testing with behat, selenium, phantom js and nightwatch.js (5)
Automate testing with behat, selenium, phantom js and nightwatch.js (5)
Faichi Solutions
 
Building testable chrome extensions
Building testable chrome extensionsBuilding testable chrome extensions
Building testable chrome extensions
Seth McLaughlin
 
APIs: A Better Alternative to Page Objects
APIs: A Better Alternative to Page ObjectsAPIs: A Better Alternative to Page Objects
APIs: A Better Alternative to Page Objects
Sauce Labs
 
Automated Testing in Angular Slides
Automated Testing in Angular SlidesAutomated Testing in Angular Slides
Automated Testing in Angular Slides
Jim Lynch
 
Automation Abstraction Layers: Page Objects and Beyond
Automation Abstraction Layers: Page Objects and BeyondAutomation Abstraction Layers: Page Objects and Beyond
Automation Abstraction Layers: Page Objects and Beyond
Alan Richardson
 
Test-driven Development with Drupal and Codeception (DrupalCamp Brighton)
Test-driven Development with Drupal and Codeception (DrupalCamp Brighton)Test-driven Development with Drupal and Codeception (DrupalCamp Brighton)
Test-driven Development with Drupal and Codeception (DrupalCamp Brighton)
Cogapp
 

What's hot (20)

ForwardJS 2017 - Fullstack end-to-end Test Automation with node.js
ForwardJS 2017 -  Fullstack end-to-end Test Automation with node.jsForwardJS 2017 -  Fullstack end-to-end Test Automation with node.js
ForwardJS 2017 - Fullstack end-to-end Test Automation with node.js
 
Testing nightwatch, by David Torroija
Testing nightwatch, by David TorroijaTesting nightwatch, by David Torroija
Testing nightwatch, by David Torroija
 
Night Watch with QA
Night Watch with QANight Watch with QA
Night Watch with QA
 
Protractor Tutorial Quality in Agile 2015
Protractor Tutorial Quality in Agile 2015Protractor Tutorial Quality in Agile 2015
Protractor Tutorial Quality in Agile 2015
 
Automated Web Testing using JavaScript
Automated Web Testing using JavaScriptAutomated Web Testing using JavaScript
Automated Web Testing using JavaScript
 
Front-end Automated Testing
Front-end Automated TestingFront-end Automated Testing
Front-end Automated Testing
 
Carmen Popoviciu - Protractor styleguide | Codemotion Milan 2015
Carmen Popoviciu - Protractor styleguide | Codemotion Milan 2015Carmen Popoviciu - Protractor styleguide | Codemotion Milan 2015
Carmen Popoviciu - Protractor styleguide | Codemotion Milan 2015
 
Testing frontends with nightwatch & saucelabs
Testing frontends with nightwatch & saucelabsTesting frontends with nightwatch & saucelabs
Testing frontends with nightwatch & saucelabs
 
Unit-testing and E2E testing in JS
Unit-testing and E2E testing in JSUnit-testing and E2E testing in JS
Unit-testing and E2E testing in JS
 
Real World Selenium Testing
Real World Selenium TestingReal World Selenium Testing
Real World Selenium Testing
 
AngularJS and Protractor
AngularJS and ProtractorAngularJS and Protractor
AngularJS and Protractor
 
Webdriver cheatsheets summary
Webdriver cheatsheets summaryWebdriver cheatsheets summary
Webdriver cheatsheets summary
 
Automated Smoke Tests with Protractor
Automated Smoke Tests with ProtractorAutomated Smoke Tests with Protractor
Automated Smoke Tests with Protractor
 
JavaScript Testing VIA Selenium
JavaScript Testing VIA SeleniumJavaScript Testing VIA Selenium
JavaScript Testing VIA Selenium
 
Automate testing with behat, selenium, phantom js and nightwatch.js (5)
Automate testing with behat, selenium, phantom js and nightwatch.js (5)Automate testing with behat, selenium, phantom js and nightwatch.js (5)
Automate testing with behat, selenium, phantom js and nightwatch.js (5)
 
Building testable chrome extensions
Building testable chrome extensionsBuilding testable chrome extensions
Building testable chrome extensions
 
APIs: A Better Alternative to Page Objects
APIs: A Better Alternative to Page ObjectsAPIs: A Better Alternative to Page Objects
APIs: A Better Alternative to Page Objects
 
Automated Testing in Angular Slides
Automated Testing in Angular SlidesAutomated Testing in Angular Slides
Automated Testing in Angular Slides
 
Automation Abstraction Layers: Page Objects and Beyond
Automation Abstraction Layers: Page Objects and BeyondAutomation Abstraction Layers: Page Objects and Beyond
Automation Abstraction Layers: Page Objects and Beyond
 
Test-driven Development with Drupal and Codeception (DrupalCamp Brighton)
Test-driven Development with Drupal and Codeception (DrupalCamp Brighton)Test-driven Development with Drupal and Codeception (DrupalCamp Brighton)
Test-driven Development with Drupal and Codeception (DrupalCamp Brighton)
 

Viewers also liked

Getting By Without "QA"
Getting By Without "QA"Getting By Without "QA"
Getting By Without "QA"
Dave King
 
Anointing to excel
Anointing to excelAnointing to excel
Anointing to excel
Tolulope Ilori
 
DrupalCon Dublin 2016 - Automated browser testing with Nightwatch.js
DrupalCon Dublin 2016 - Automated browser testing with Nightwatch.jsDrupalCon Dublin 2016 - Automated browser testing with Nightwatch.js
DrupalCon Dublin 2016 - Automated browser testing with Nightwatch.js
Vladimir Roudakov
 
The Javascript Toolkit 2.0
The Javascript Toolkit 2.0The Javascript Toolkit 2.0
The Javascript Toolkit 2.0
Marcos Vinícius
 
Evolving legacy to microservices and ddd
Evolving legacy to microservices and dddEvolving legacy to microservices and ddd
Evolving legacy to microservices and ddd
Marcos Vinícius
 
Fashion Forward_ VIVACITY 7
Fashion Forward_ VIVACITY 7Fashion Forward_ VIVACITY 7
Fashion Forward_ VIVACITY 7
Arun Khanna
 
Анастасия Войтова: Здоровая психологическая атмосфера в жизни разработчика, ...
Анастасия Войтова:  Здоровая психологическая атмосфера в жизни разработчика, ...Анастасия Войтова:  Здоровая психологическая атмосфера в жизни разработчика, ...
Анастасия Войтова: Здоровая психологическая атмосфера в жизни разработчика, ...
Fwdays
 
Benchmark Morgages, Inc. Now Hiring
Benchmark Morgages, Inc. Now HiringBenchmark Morgages, Inc. Now Hiring
Benchmark Morgages, Inc. Now Hiring
Benchmark Mortgages, Inc.
 
Indie Music for the Indie Writer: A Productivity Playlist by Scribendi.com
Indie Music for the Indie Writer: A Productivity Playlist by Scribendi.com Indie Music for the Indie Writer: A Productivity Playlist by Scribendi.com
Indie Music for the Indie Writer: A Productivity Playlist by Scribendi.com
Scribendi
 
Romanticism
RomanticismRomanticism
Romanticism
phebeshen
 
Photography
Photography Photography
Photography
Jacob J
 

Viewers also liked (11)

Getting By Without "QA"
Getting By Without "QA"Getting By Without "QA"
Getting By Without "QA"
 
Anointing to excel
Anointing to excelAnointing to excel
Anointing to excel
 
DrupalCon Dublin 2016 - Automated browser testing with Nightwatch.js
DrupalCon Dublin 2016 - Automated browser testing with Nightwatch.jsDrupalCon Dublin 2016 - Automated browser testing with Nightwatch.js
DrupalCon Dublin 2016 - Automated browser testing with Nightwatch.js
 
The Javascript Toolkit 2.0
The Javascript Toolkit 2.0The Javascript Toolkit 2.0
The Javascript Toolkit 2.0
 
Evolving legacy to microservices and ddd
Evolving legacy to microservices and dddEvolving legacy to microservices and ddd
Evolving legacy to microservices and ddd
 
Fashion Forward_ VIVACITY 7
Fashion Forward_ VIVACITY 7Fashion Forward_ VIVACITY 7
Fashion Forward_ VIVACITY 7
 
Анастасия Войтова: Здоровая психологическая атмосфера в жизни разработчика, ...
Анастасия Войтова:  Здоровая психологическая атмосфера в жизни разработчика, ...Анастасия Войтова:  Здоровая психологическая атмосфера в жизни разработчика, ...
Анастасия Войтова: Здоровая психологическая атмосфера в жизни разработчика, ...
 
Benchmark Morgages, Inc. Now Hiring
Benchmark Morgages, Inc. Now HiringBenchmark Morgages, Inc. Now Hiring
Benchmark Morgages, Inc. Now Hiring
 
Indie Music for the Indie Writer: A Productivity Playlist by Scribendi.com
Indie Music for the Indie Writer: A Productivity Playlist by Scribendi.com Indie Music for the Indie Writer: A Productivity Playlist by Scribendi.com
Indie Music for the Indie Writer: A Productivity Playlist by Scribendi.com
 
Romanticism
RomanticismRomanticism
Romanticism
 
Photography
Photography Photography
Photography
 

Similar to Nightwatch at Tilt

Turn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modulesTurn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modules
jerryorr
 
ApacheCon 2005
ApacheCon 2005ApacheCon 2005
ApacheCon 2005
Adam Trachtenberg
 
Better Testing With PHP Unit
Better Testing With PHP UnitBetter Testing With PHP Unit
Better Testing With PHP Unit
sitecrafting
 
BPM-3 Advanced Workflow Deep Dive
BPM-3 Advanced Workflow Deep DiveBPM-3 Advanced Workflow Deep Dive
BPM-3 Advanced Workflow Deep Dive
Alfresco Software
 
How I Became a WordPress Hacker
How I Became a WordPress HackerHow I Became a WordPress Hacker
How I Became a WordPress Hacker
Mike Zielonka
 
Building Things Fast - and getting approval
Building Things Fast - and getting approvalBuilding Things Fast - and getting approval
Building Things Fast - and getting approval
Simon Willison
 
Service Worker - Reliability bits
Service Worker - Reliability bitsService Worker - Reliability bits
Service Worker - Reliability bits
jungkees
 
FamilySearch Reference Client
FamilySearch Reference ClientFamilySearch Reference Client
FamilySearch Reference Client
Dallan Quass
 
Effectively Testing Services - Burlington Ruby Conf
Effectively Testing Services - Burlington Ruby ConfEffectively Testing Services - Burlington Ruby Conf
Effectively Testing Services - Burlington Ruby Conf
neal_kemp
 
20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdev20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdev
Frank Rousseau
 
Introduction to Selenium and Ruby
Introduction to Selenium and RubyIntroduction to Selenium and Ruby
Introduction to Selenium and Ruby
Ynon Perek
 
Selenium bootcamp slides
Selenium bootcamp slides   Selenium bootcamp slides
Selenium bootcamp slides
seleniumbootcamp
 
PWA 與 Service Worker
PWA 與 Service WorkerPWA 與 Service Worker
PWA 與 Service Worker
Anna Su
 
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
崇之 清水
 
The Art of AngularJS in 2015 - Angular Summit 2015
The Art of AngularJS in 2015 - Angular Summit 2015The Art of AngularJS in 2015 - Angular Summit 2015
The Art of AngularJS in 2015 - Angular Summit 2015
Matt Raible
 
Deploying Next Gen Systems with Zero Downtime
Deploying Next Gen Systems with Zero DowntimeDeploying Next Gen Systems with Zero Downtime
Deploying Next Gen Systems with Zero Downtime
Twilio Inc
 
How to implement authorization in your backend with AWS IAM
How to implement authorization in your backend with AWS IAMHow to implement authorization in your backend with AWS IAM
How to implement authorization in your backend with AWS IAM
Provectus
 
Guard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityGuard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful Security
Ryan Weaver
 
How to build Client Side Applications with WordPress and WP-API | #wcmia
How to build Client Side Applications with WordPress and WP-API | #wcmiaHow to build Client Side Applications with WordPress and WP-API | #wcmia
How to build Client Side Applications with WordPress and WP-API | #wcmia
Roy Sivan
 
PWA Roadshow Korea - Service Worker
PWA Roadshow Korea - Service WorkerPWA Roadshow Korea - Service Worker
PWA Roadshow Korea - Service Worker
jungkees
 

Similar to Nightwatch at Tilt (20)

Turn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modulesTurn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modules
 
ApacheCon 2005
ApacheCon 2005ApacheCon 2005
ApacheCon 2005
 
Better Testing With PHP Unit
Better Testing With PHP UnitBetter Testing With PHP Unit
Better Testing With PHP Unit
 
BPM-3 Advanced Workflow Deep Dive
BPM-3 Advanced Workflow Deep DiveBPM-3 Advanced Workflow Deep Dive
BPM-3 Advanced Workflow Deep Dive
 
How I Became a WordPress Hacker
How I Became a WordPress HackerHow I Became a WordPress Hacker
How I Became a WordPress Hacker
 
Building Things Fast - and getting approval
Building Things Fast - and getting approvalBuilding Things Fast - and getting approval
Building Things Fast - and getting approval
 
Service Worker - Reliability bits
Service Worker - Reliability bitsService Worker - Reliability bits
Service Worker - Reliability bits
 
FamilySearch Reference Client
FamilySearch Reference ClientFamilySearch Reference Client
FamilySearch Reference Client
 
Effectively Testing Services - Burlington Ruby Conf
Effectively Testing Services - Burlington Ruby ConfEffectively Testing Services - Burlington Ruby Conf
Effectively Testing Services - Burlington Ruby Conf
 
20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdev20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdev
 
Introduction to Selenium and Ruby
Introduction to Selenium and RubyIntroduction to Selenium and Ruby
Introduction to Selenium and Ruby
 
Selenium bootcamp slides
Selenium bootcamp slides   Selenium bootcamp slides
Selenium bootcamp slides
 
PWA 與 Service Worker
PWA 與 Service WorkerPWA 與 Service Worker
PWA 與 Service Worker
 
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
 
The Art of AngularJS in 2015 - Angular Summit 2015
The Art of AngularJS in 2015 - Angular Summit 2015The Art of AngularJS in 2015 - Angular Summit 2015
The Art of AngularJS in 2015 - Angular Summit 2015
 
Deploying Next Gen Systems with Zero Downtime
Deploying Next Gen Systems with Zero DowntimeDeploying Next Gen Systems with Zero Downtime
Deploying Next Gen Systems with Zero Downtime
 
How to implement authorization in your backend with AWS IAM
How to implement authorization in your backend with AWS IAMHow to implement authorization in your backend with AWS IAM
How to implement authorization in your backend with AWS IAM
 
Guard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityGuard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful Security
 
How to build Client Side Applications with WordPress and WP-API | #wcmia
How to build Client Side Applications with WordPress and WP-API | #wcmiaHow to build Client Side Applications with WordPress and WP-API | #wcmia
How to build Client Side Applications with WordPress and WP-API | #wcmia
 
PWA Roadshow Korea - Service Worker
PWA Roadshow Korea - Service WorkerPWA Roadshow Korea - Service Worker
PWA Roadshow Korea - Service Worker
 

Recently uploaded

OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata
 
Transform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR SolutionsTransform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR Solutions
TheSMSPoint
 
E-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet DynamicsE-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet Dynamics
Hornet Dynamics
 
openEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain SecurityopenEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain Security
Shane Coughlan
 
Webinar On-Demand: Using Flutter for Embedded
Webinar On-Demand: Using Flutter for EmbeddedWebinar On-Demand: Using Flutter for Embedded
Webinar On-Demand: Using Flutter for Embedded
ICS
 
DDS-Security 1.2 - What's New? Stronger security for long-running systems
DDS-Security 1.2 - What's New? Stronger security for long-running systemsDDS-Security 1.2 - What's New? Stronger security for long-running systems
DDS-Security 1.2 - What's New? Stronger security for long-running systems
Gerardo Pardo-Castellote
 
GraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph TechnologyGraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph Technology
Neo4j
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Łukasz Chruściel
 
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
rickgrimesss22
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
Rakesh Kumar R
 
Oracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptxOracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptx
Remote DBA Services
 
APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)
Boni García
 
Hand Rolled Applicative User Validation Code Kata
Hand Rolled Applicative User ValidationCode KataHand Rolled Applicative User ValidationCode Kata
Hand Rolled Applicative User Validation Code Kata
Philip Schwarz
 
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Crescat
 
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit ParisNeo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j
 
SWEBOK and Education at FUSE Okinawa 2024
SWEBOK and Education at FUSE Okinawa 2024SWEBOK and Education at FUSE Okinawa 2024
SWEBOK and Education at FUSE Okinawa 2024
Hironori Washizaki
 
May Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdfMay Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdf
Adele Miller
 
What is Augmented Reality Image Tracking
What is Augmented Reality Image TrackingWhat is Augmented Reality Image Tracking
What is Augmented Reality Image Tracking
pavan998932
 
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise EditionWhy Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Envertis Software Solutions
 
Energy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina JonuziEnergy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina Jonuzi
Green Software Development
 

Recently uploaded (20)

OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024
 
Transform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR SolutionsTransform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR Solutions
 
E-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet DynamicsE-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet Dynamics
 
openEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain SecurityopenEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain Security
 
Webinar On-Demand: Using Flutter for Embedded
Webinar On-Demand: Using Flutter for EmbeddedWebinar On-Demand: Using Flutter for Embedded
Webinar On-Demand: Using Flutter for Embedded
 
DDS-Security 1.2 - What's New? Stronger security for long-running systems
DDS-Security 1.2 - What's New? Stronger security for long-running systemsDDS-Security 1.2 - What's New? Stronger security for long-running systems
DDS-Security 1.2 - What's New? Stronger security for long-running systems
 
GraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph TechnologyGraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph Technology
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
 
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
 
Oracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptxOracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptx
 
APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)
 
Hand Rolled Applicative User Validation Code Kata
Hand Rolled Applicative User ValidationCode KataHand Rolled Applicative User ValidationCode Kata
Hand Rolled Applicative User Validation Code Kata
 
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
 
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit ParisNeo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
 
SWEBOK and Education at FUSE Okinawa 2024
SWEBOK and Education at FUSE Okinawa 2024SWEBOK and Education at FUSE Okinawa 2024
SWEBOK and Education at FUSE Okinawa 2024
 
May Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdfMay Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdf
 
What is Augmented Reality Image Tracking
What is Augmented Reality Image TrackingWhat is Augmented Reality Image Tracking
What is Augmented Reality Image Tracking
 
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise EditionWhy Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
 
Energy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina JonuziEnergy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina Jonuzi
 

Nightwatch at Tilt

  • 1. Nightwatch at Tilt San Francisco Selenium Meetup March 4th, 2015
  • 2. About Me • NJ -> UIUC -> Penn State -> Blacksburg VA -> SF Bay Area • Grad School -> WebDev -> DevOps Lead -> Frontend Lead • Java -> Python -> JavaScript • @tildedave • Blog, etc: tildedave.com San Francisco Selenium Meetup March 4th 2014
  • 3. Tilt Make Amazing Things Happen San Francisco Selenium Meetup March 4th 2014
  • 4. Tilt is a social crowd-funding company San Francisco Selenium Meetup March 4th 2014
  • 5. San Francisco Selenium Meetup March 4th 2014
  • 6. “Move Fast and Break Things” It turns out that this statement is a lie San Francisco Selenium Meetup March 4th 2014
  • 7. Golden Features • Login • Signup • Contribution Flow • Commenting • Admin Payouts • … really no user flow can ever break acceptably San Francisco Selenium Meetup March 4th 2014
  • 8. Selenium at Tilt San Francisco Selenium Meetup March 4th 2014
  • 9. History of Selenium at Tilt • CI/CD environment - push code to production daily • No dedicated QA resources as part of the development team • Must not break core flows San Francisco Selenium Meetup March 4th 2014
  • 10. History of Selenium at Tilt • Pre-History: PhantomJS/PhantomProxy - no visibility on failures • February 2013 - Introduce Selenium for functional testing (2.31.0) • June 2014 - Selenium tests vs staging/production as a ‘health check’ of deployed code (2.42.2) San Francisco Selenium Meetup March 4th 2014
  • 11. Ancient Code: Phantom JS ! promiseIt('can contribute to regular campaign', function(p) {! return p! .withPrimedCampaign()! .thenOpenCampaignPage()! .thenLightboxClick('.campaign-tilt-info .btn')! .thenType('#amount_lightbox', '2.00')! .thenClickAndWaitForDocumentReady('#contribute-continue')! .thenVerifyElementContents('#display-total', '2.05')! .thenFillCCForm()! .thenClickAndWaitAndFailIfLightboxCloses('#confirm-btn')! .thenWait(1000)! .thenVerifyElementVisible('#just_contributed')! .thenCancelCampaign();! });! ! San Francisco Selenium Meetup March 4th 2014
  • 12. Today: Nightwatch Tests 'Can contribute as admin': function(client) {! var selectors = client.page.campaign().selectors;! client.page.homepage().load()! .createFBUserAndLogIn()! .createCampaignAPI({}, function(campaign) {! return client.page.campaign().load(campaign.title);! })! .page.campaign().clickContribute()! .page.contributionFlow().enterContributionAmount('2')! .page.contributionFlow().checkOut()! .page.contributionFlow().skipInviteAndShare()! // admins don't get asked to comment! .verify.elementNotPresent(selectors.lightboxTitle)! .end();! }! San Francisco Selenium Meetup March 4th 2014
  • 13. Nightwatch at Tilt • September 2014 • Selenium suite run on every branch before merge • Lots of flapping tests - developers often rerun tests until green • Test suite expansion seems like a nightmare - lots of selectors in tests, copy/pasted setup, etc • October 2014 - We start investigating better solutions San Francisco Selenium Meetup March 4th 2014
  • 14. Nightwatch.js San Francisco Selenium Meetup March 4th 2014
  • 15. Nightwatch • http://nightwatchjs.org/ • Better interface to selenium-webdriver • Library provides Custom Commands, Page Objects, and Assertions • It’s in JavaScript! San Francisco Selenium Meetup March 4th 2014
  • 16. Why Nightwatch for Tilt? • It’s in JavaScript • Using Ruby just for tests is a hard sell • Easily use npm modules as part of your tests • Builds in important concepts that Tilt had rolled itself (custom commands) or should have (page objects) • Old suite had too much technical debt to be saved San Francisco Selenium Meetup March 4th 2014
  • 17. Tiltcabulary • Users - users of the site • Campaigns - crowdfunding campaigns San Francisco Selenium Meetup March 4th 2014
  • 18. Basic Nightwatch Test for tilt.com San Francisco Selenium Meetup March 4th 2014
  • 19. Basic Nightwatch Test for tilt.com module.exports = {! 'Tilt.com': function(client) {! var title = 'Collect money from your group';! client! .url('https://www.tilt.com')! .waitForElementVisible('.hero-title', 1000)! .verify.containsText('.hero-title',! title)! .end();! }! };! San Francisco Selenium Meetup March 4th 2014
  • 20. Basic Nightwatch Test for tilt.com module.exports = {! 'Tilt.com': function(client) {! var title = 'Collect money from your group';! client! .url('https://www.tilt.com')! .waitForElementVisible('.hero-title', 1000)! .verify.containsText('.hero-title',! title)! .end();! }! };! San Francisco Selenium Meetup March 4th 2014 Arrange
  • 21. Basic Nightwatch Test for tilt.com module.exports = {! 'Tilt.com': function(client) {! var title = 'Collect money from your group';! client! .url('https://www.tilt.com')! .waitForElementVisible('.hero-title', 1000)! .verify.containsText('.hero-title',! title)! .end();! }! };! San Francisco Selenium Meetup March 4th 2014 Assert
  • 22. Basic Nightwatch Test for tilt.com • We have a video on our homepage. Probably it shouldn’t break.
 
 
 
 
 
 
 
 San Francisco Selenium Meetup March 4th 2014
  • 23. Basic Nightwatch Test for tilt.com San Francisco Selenium Meetup March 4th 2014
  • 24. Basic Nightwatch Test for tilt.com module.exports = {! 'Tilt.com Video': function(client) {! client! .url('https://www.tilt.com')! .waitForElementVisible(‘.video-link', 1000)! .pause(3000) // vidyard JS must have loaded! .click('.video-link')! .waitForElementVisible('.vidyard_tclose', 3000)! .click('.vidyard_tclose')! .end();! }! };! San Francisco Selenium Meetup March 4th 2014
  • 25. Basic Nightwatch Test for tilt.com module.exports = {! 'Tilt.com Video': function(client) {! client! .url('https://www.tilt.com')! .waitForElementVisible(‘.video-link', 1000)! .pause(3000) // vidyard JS must have loaded! .click('.video-link')! .waitForElementVisible('.vidyard_tclose', 3000)! .click('.vidyard_tclose')! .end();! }! };! San Francisco Selenium Meetup March 4th 2014 Arrange
  • 26. Basic Nightwatch Test for tilt.com module.exports = {! 'Tilt.com Video': function(client) {! client! .url('https://www.tilt.com')! .waitForElementVisible(‘.video-link', 1000)! .pause(3000) // vidyard JS must have loaded! .click('.video-link')! .waitForElementVisible('.vidyard_tclose', 3000)! .click('.vidyard_tclose')! .end();! }! };! San Francisco Selenium Meetup March 4th 2014 Act
  • 27. Basic Nightwatch Test for tilt.com module.exports = {! 'Tilt.com Video': function(client) {! client! .url('https://www.tilt.com')! .waitForElementVisible(‘.video-link', 1000)! .pause(3000) // vidyard JS must have loaded! .click('.video-link')! .waitForElementVisible('.vidyard_tclose', 3000)! .click('.vidyard_tclose')! .end();! }! };! San Francisco Selenium Meetup March 4th 2014 Assert
  • 28. Basic Homepage Page Object module.exports = function (client) {! var selectors = {! title: '.hero-title',! video: '.vidyard_tbox',! videoLink: '.video-link',! videoClose: '.vidyard_tclose'! };! this.selectors = selectors;! ! this.openVideo = function() {! return client! .waitForElementVisible(selectors.videoLink, 1000)! .click(selectors.videoLink)! .waitForElementVisible(selectors.videoClose, 5000);! };! ! this.closeVideo = function() {! return client! .waitForElementVisible(selectors.videoClose, 1000)! .click(selectors.videoClose)! .waitForElementNotVisible(selectors.videoClose, 5000);! };! };! San Francisco Selenium Meetup March 4th 2014
  • 29. Basic Homepage Page Object module.exports = function (client) {! var selectors = {! title: '.hero-title',! video: '.vidyard_tbox',! videoLink: '.video-link',! videoClose: '.vidyard_tclose'! };! this.selectors = selectors;! ! this.openVideo = function() {! return client! .waitForElementVisible(selectors.videoLink, 1000)! .click(selectors.videoLink)! .waitForElementVisible(selectors.videoClose, 5000);! };! ! this.closeVideo = function() {! return client! .waitForElementVisible(selectors.videoClose, 1000)! .click(selectors.videoClose)! .waitForElementNotVisible(selectors.videoClose, 5000);! };! };! San Francisco Selenium Meetup March 4th 2014 Unify DOM selectors
 as variables
  • 30. Basic Homepage Page Object module.exports = function (client) {! var selectors = {! title: '.hero-title',! video: '.vidyard_tbox',! videoLink: '.video-link',! videoClose: '.vidyard_tclose'! };! this.selectors = selectors;! ! this.openVideo = function() {! return client! .waitForElementVisible(selectors.videoLink, 1000)! .click(selectors.videoLink)! .waitForElementVisible(selectors.videoClose, 5000);! };! ! this.closeVideo = function() {! return client! .waitForElementVisible(selectors.videoClose, 1000)! .click(selectors.videoClose)! .waitForElementNotVisible(selectors.videoClose, 5000);! };! };! San Francisco Selenium Meetup March 4th 2014 Utility Methods for Tests
  • 31. Basic Page Objects module.exports = {! ! 'Tilt.com Video': function(client) {! var title = 'Collect money from your group';! client! .url(‘https://www.tilt.com')! .page.homepage().openVideo()! .verify.elementPresent(! client.page.homepage().selectors.video! )! .page.homepage().closeVideo()! .end();! }! ! };! San Francisco Selenium Meetup March 4th 2014
  • 32. Basic Page Objects module.exports = {! ! 'Tilt.com Video': function(client) {! var title = 'Collect money from your group';! client! .url(‘https://www.tilt.com')! .page.homepage().openVideo()! .verify.elementPresent(! client.page.homepage().selectors.video! )! .page.homepage().closeVideo()! .end();! }! ! };! San Francisco Selenium Meetup March 4th 2014 No selectors in tests
  • 33. Basic Page Objects module.exports = {! ! 'Tilt.com Video': function(client) {! var title = 'Collect money from your group';! client! .url(‘https://www.tilt.com')! .page.homepage().openVideo()! .verify.elementPresent(! client.page.homepage().selectors.video! )! .page.homepage().closeVideo()! .end();! }! ! };! San Francisco Selenium Meetup March 4th 2014 Waits common to the page now inside the page object
  • 34. Why Nightwatch? • Three features you would otherwise build yourself • Page Objects • Custom Commands • Custom Assertions San Francisco Selenium Meetup March 4th 2014
  • 35. Page Objects • Basic design pattern - abstract page behavior out of selectors • Add in common functions for interacting with page • In our repo: abstract different desktop/mobile behavior into the page object San Francisco Selenium Meetup March 4th 2014
  • 36. Page Object Example: “Contribution Flow” this.enterContributionAmount = function(amount) {! var sels = (client.globals.isDesktop) ?! selectors.desktop : selectors.mobile;! return client! .waitForElementVisible(sels.contributeAmountField,! client.globals.timeout)! .setValue(sels.contributeAmountField, amount)! .pause(500)! .click(seles.contributeStep1Submit)! .waitForElementNotVisible(! sels.contributeStep1Submit,! client.globals.timeout! );! };! San Francisco Selenium Meetup March 4th 2014
  • 37. Page Objects: Desktop vs Mobile San Francisco Selenium Meetup March 4th 2014
  • 38. Page Objects: Desktop vs Mobile San Francisco Selenium Meetup March 4th 2014 Expiration is
 two fields Expiration is 
 one field
  • 39. Page Objects: Desktop vs Mobile this.enterCreditCard = function(cardNumber, expirationMonth,! expirationYear, cvc, zip) {! var platformSelectors = (client.globals.isDesktop) ?! selectors.desktop :! selectors.mobile;! var d = client! .waitForElementVisible(platformSelectors.cardNumber,! client.globals.timeout)! .setValue(platformSelectors.cardNumber,! [cardNumber, client.Keys.TAB]);! if (client.globals.isDesktop) {! d = d.setValue(platformSelectors.expiration,! [expirationMonth + '/' + expirationYear,! client.Keys.TAB]);! } else {! d = d! .setValue(platformSelectors.expirationMonth, [expirationMonth,! client.Keys.TAB])! .setValue(platformSelectors.expirationYear, [expirationYear,! client.Keys.TAB]);! }! return d! .setValue(platformSelectors.cvc, [cvc, client.Keys.TAB])! .setValue(platformSelectors.zip, [zip, client.Keys.TAB]);! }! San Francisco Selenium Meetup March 4th 2014
  • 40. Custom Commands • Build business-specific language for your tests • Example commands from our repository: • createEmailUser • createEmailUserAndLogIn • createFacebookTestUser • setCountry San Francisco Selenium Meetup March 4th 2014
  • 41. Custom Assertions • Add specific assertions to your tests • We don’t use these as much - examples from our repo: • isLoggedIn • linkMatches(text, href) • lightboxHasHeader San Francisco Selenium Meetup March 4th 2014
  • 42. Test Suite Benefits San Francisco Selenium Meetup March 4th 2014
  • 43. Bootstrapping JavaScript • Tilt runs on a hybrid stack • Old code uses jQuery/jQuery UI for frontend widgets • New code uses React • Server-side rendering with a node.js service San Francisco Selenium Meetup March 4th 2014
  • 44. Server-side Rendering Challenges • Elements in the DOM but not functional • Elements visible but not functional San Francisco Selenium Meetup March 4th 2014
  • 45. Opening the User Menu San Francisco Selenium Meetup March 4th 2014
  • 46. Opening the User Menu this.openUserMenu = function(callback) {! return client! .waitForElementVisible(! this.selectors.menuToggle,! client.globals.timeout! )! // completely arbitrary wait time so that menu JS ! // initializes! .pause(5000)! .click(this.selectors.menuToggle)! .waitForElementVisible('.user-menu', 1000, callback);! };! San Francisco Selenium Meetup March 4th 2014
  • 47. Opening the User Menu this.openUserMenu = function(callback) {! return client! .waitForElementVisible(! this.selectors.menuToggle,! client.globals.timeout! )! // completely arbitrary wait time so that menu JS ! // initializes! .pause(5000)! .click(this.selectors.menuToggle)! .waitForElementVisible('.user-menu', 1000, callback);! };! San Francisco Selenium Meetup March 4th 2014 JavaScript must have initialized before menu is functional!
  • 48. Old Code window.rewireReact = function() {! $('[data-mount-as]').each(function() {! var $this = $(this),! name = $this.attr('data-mount-as'),! props = JSON.parse($this.attr('data-props'));! ! $this.removeAttr('data-mount-as');! ! // This causes event handlers on the component ! // to become functional! var component = ReactComponents[name];! React.render(React.createElement(component, props),! $this.get(0));! });! };! ! $(document).ready(window.rewireReact); San Francisco Selenium Meetup March 4th 2014
  • 49. Old Code window.rewireReact = function() {! $('[data-mount-as]').each(function() {! var $this = $(this),! name = $this.attr('data-mount-as'),! props = JSON.parse($this.attr('data-props'));! ! $this.removeAttr('data-mount-as');! ! // This causes event handlers on the component ! // to become functional! var component = ReactComponents[name];! React.render(React.createElement(component, props),! $this.get(0));! });! };! ! $(document).ready(window.rewireReact); Menus only functional after document ready! San Francisco Selenium Meetup March 4th 2014
  • 50. New Code <!-- Tilt JavaScript bundle -->! <script src="https://d25y59nqso5bzg.cloudfront.net/built/home- ce348751.js"></script>! <!-- all JS is loaded, make the page functional -->! <script type=“text/javascript”>window.rewireReact();</script>! San Francisco Selenium Meetup March 4th 2014
  • 51. New Code <!-- Tilt JavaScript bundle -->! <script src="https://d25y59nqso5bzg.cloudfront.net/built/home- ce348751.js"></script>! <!-- all JS is loaded, make the page functional -->! <script type=“text/javascript”>window.rewireReact();</script>! No more sticky menus! San Francisco Selenium Meetup March 4th 2014
  • 52. Test Suite Suggestions in case you are green-fielding a new test suite San Francisco Selenium Meetup March 4th 2014
  • 53. Develop and run tests against an integration environment Staging, production, etc - not someone’s local box San Francisco Selenium Meetup March 4th 2014
  • 54. Run Tests Constantly San Francisco Selenium Meetup March 4th 2014
  • 55. Run Tests Constantly • We run our tests every 10 minutes against staging • When you add a wait time to a test you have asserted that your system always responds in that amount of time • See how tests behave in an integration environment and adjust San Francisco Selenium Meetup March 4th 2014
  • 56. Happy Path Tests First Sad path tests … eventually San Francisco Selenium Meetup March 4th 2014
  • 57. Single Responsibility Page Objects San Francisco Selenium Meetup March 4th 2014
  • 58. Page Objects… • Don’t do test setup • they don’t make users • they don’t make campaigns • Don’t orchestrate complex flows between pages • Do one thing and one thing only • (yes this puts more verbosity into your tests) San Francisco Selenium Meetup March 4th 2014
  • 59. Problems We’ve Had With Nightwatch your mileage may vary! San Francisco Selenium Meetup March 4th 2014
  • 60. Hard to run an individual test Something like mocha —grep would be really great
 (currently I just comment out tests) San Francisco Selenium Meetup March 4th 2014
  • 61. No Page Object Documentation Yet We had to dig through the repo to really understand how to use these San Francisco Selenium Meetup March 4th 2014
  • 62. Nondeterminstic Behavior Page objects sometimes inherit a stale selenium session, repeating “stale element exception” Use —verbose to see what’s happening if you are really stumped San Francisco Selenium Meetup March 4th 2014
  • 63. waitForElementVisible failures When running an individual test file, a waitForElementVisible failure causes all the rest of the tests to be skipped San Francisco Selenium Meetup March 4th 2014
  • 64. Nightwatch Pull Requests I Really Want Merged • Distinguish between test failures and selenium errors when taking screenshots: https://github.com/ beatfactor/nightwatch/pull/316 • Run individual test files in parallel with test workers https://github.com/beatfactor/nightwatch/pull/317 San Francisco Selenium Meetup March 4th 2014
  • 65. Next Steps for Nightwatch at Tilt • Replicate full functionality of old suite • Cross-browser testing with Saucelabs • Shard test suite (currently 2 jobs) into specific suites: • Selenium-Nightwatch-Contribution, Selenium- Nightwatch-Login, etc. San Francisco Selenium Meetup March 4th 2014
  • 66. Thank You! • Questions? San Francisco Selenium Meetup March 4th 2014