SlideShare ist ein Scribd-Unternehmen logo
1 von 71
Downloaden Sie, um offline zu lesen
jakobm.com
@jakobmattsson
I’m a coder first and foremost. I also help
companies recruit coders, train coders and
architect software. Sometimes I do technical
due diligence and speak at conferences.
!
Want more? Read my story or blog.
Social
coding
FishBrain is the fastest, easiest way
to log and share your fishing.

!
Get instant updates from anglers on
nearby lakes, rivers, and the coast.
Testing web APIs
Simple and readable
Example - Testing a blog API
• Create a blog
• Create two blog entries
• Create two users
• Create a lotal of three comments from
those users, on the two posts
• Request the stats for the blog and
check if the given number of entries
and comments are correct
post('/blogs', {
name: 'My blog'
}, function(err, blog) {
! post(concatUrl('blogs', blog.id, 'entries'), {
title: 'my first post’,
body: 'Here is the text of my first post'
}, function(err, entry1) {
! post(concatUrl('blogs', blog.id, 'entries'), {
title: 'my second post’,
body: 'I do not know what to write any more...'
}, function(err, entry2) {
! post('/user', {
name: 'john doe’
}, function(err, visitor1) {
! post('/user', {
name: 'jane doe'
}, function(err, visitor2) {
! post('/comments', {
userId: visitor1.id,
entryId: entry1.id,
text: "well written dude"
}, function(err, comment1) {
! post('/comments', {
userId: visitor2.id,
entryId: entry1.id,
text: "like it!"
}, function(err, comment2) {
! post('/comments', {
userId: visitor2.id,
entryId: entry2.id,
text: "nah, crap"
}, function(err, comment3) {
! get(concatUrl('blogs', blog.id), function(err, blogInfo) {
assertEquals(blogInfo, {
name: 'My blog',
numberOfEntries: 2,
numberOfComments: 3
});
});
});
});
});
});
});
});
});
});
*No, this is not a tutorial
Promises 101*
getJSON({
url: '/somewhere/over/the/rainbow',
success: function(result) {
// deal with it
}
});
getJSON({
url: '/somewhere/over/the/rainbow',
success: function(result) {
// deal with it
}
});
rainbows.then(function(result) {
// deal with it
});
var rainbows = getJSON({
url: '/somewhere/over/the/rainbow'
});
getJSON({
url: '/somewhere/over/the/rainbow',
success: function(result) {
// deal with it
}
});
rainbows.then(function(result) {
// deal with it
});
var rainbows = getJSON({
url: '/somewhere/over/the/rainbow'
});
f(rainbows);
Why is that
a good idea?
• Loosen up the coupling
• Superior error handling
• Simplified async
Why is that
a good idea?
• Loosen up the coupling
• Superior error handling
• Simplified async
But in particular, it abstracts away the temporal
dependencies in your program (or in this case, test)
That’s enough 101
(even though people barely talk about
the last - and most important - idea)
Promises are not new
Promises are not new
http://github.com/kriskowal/q
http://www.html5rocks.com/en/tutorials/es6/promises
http://domenic.me/2012/10/14/youre-missing-the-point-of-promises
http://www.promisejs.org
https://github.com/bellbind/using-promise-q
https://github.com/tildeio/rsvp.js
https://github.com/cujojs/when
They’ve even
made it into ES6
They’ve even
made it into ES6
Already implemented
natively in
Firefox 30Chrome 33
So why are you not
using them?
So why are you not
using them?
How to draw an owl
1. Draw some
circles
How to draw an owl
1. Draw some
circles
2.Draw the rest
of the owl
How to draw an owl
We want to
draw owls.
!
Not circles.
getJSON('story.json').then(function(story) {
addHtmlToPage(story.heading);
!
// Map our array of chapter urls to
// an array of chapter json promises.
// This makes sture they all download parallel.
return story.chapterUrls.map(getJSON)
.reduce(function(sequence, chapterPromise) {
// Use reduce to chain the promises together,
// adding content to the page for each chapter
return sequence.then(function() {
// Wait for everything in the sequence so far,
// then wait for this chapter to arrive.
return chapterPromise;
}).then(function(chapter) {
addHtmlToPage(chapter.html);
});
}, Promise.resolve());
}).then(function() {
addTextToPage('All done');
}).catch(function(err) {
// catch any error that happened along the way
addTextToPage("Argh, broken: " + err.message);
}).then(function() {
document.querySelector('.spinner').style.display = 'none';
});
As announced
for ES6
That’s circles.
!
Nice circles!
!
Still circles.
browser.init({browserName:'chrome'}, function() {
browser.get("http://admc.io/wd/test-pages/guinea-pig.html", function() {
browser.title(function(err, title) {
title.should.include('WD');
browser.elementById('i am a link', function(err, el) {
browser.clickElement(el, function() {
browser.eval("window.location.href", function(err, href) {
href.should.include('guinea-pig2');
browser.quit();
});
});
});
});
});
});
Node.js WebDriver
Before promises
browser
.init({ browserName: 'chrome' })
.then(function() {
return browser.get("http://admc.io/wd/test-pages/guinea-pig.html");
})
.then(function() { return browser.title(); })
.then(function(title) {
title.should.include('WD');
return browser.elementById('i am a link');
})
.then(function(el) { return browser.clickElement(el); })
.then(function() {
return browser.eval("window.location.href");
})
.then(function(href) { href.should.include('guinea-pig2'); })
.fin(function() { return browser.quit(); })
.done();
After promises
Used to be
callback-hell.
!
Now it is
then-hell.
These examples are
just a different way
of doing async.
!
It’s still uncomfortable.
It’s still circles!
The point of promises:
!
Make async code
as straightforward
as sync code
The point of promises:
1 Promises out: Always return promises -
not callback
2 Promises in: Functions should accept
promises as well as regular values
3 Promises between: Augment promises as
you augment regular objects
Three requirements
Let me elaborate
Example - Testing a blog API
• Create a blog
• Create two blog entries
• Create some users
• Create some comments from those
users, on the two posts
• Request the stats for the blog and
check if the given number of entries
and comments are correct
post('/blogs', {
name: 'My blog'
}, function(err, blog) {
! post(concatUrl('blogs', blog.id, 'entries'), {
title: 'my first post’,
body: 'Here is the text of my first post'
}, function(err, entry1) {
! post(concatUrl('blogs', blog.id, 'entries'), {
title: 'my second post’,
body: 'I do not know what to write any more...'
}, function(err, entry2) {
! post('/user', {
name: 'john doe’
}, function(err, visitor1) {
! post('/user', {
name: 'jane doe'
}, function(err, visitor2) {
! post('/comments', {
userId: visitor1.id,
entryId: entry1.id,
text: "well written dude"
}, function(err, comment1) {
! post('/comments', {
userId: visitor2.id,
entryId: entry1.id,
text: "like it!"
}, function(err, comment2) {
! post('/comments', {
userId: visitor2.id,
entryId: entry2.id,
text: "nah, crap"
}, function(err, comment3) {
! get(concatUrl('blogs', blog.id), function(err, blogInfo) {
assertEquals(blogInfo, {
name: 'My blog',
numberOfEntries: 2,
numberOfComments: 3
});
});
});
});
});
});
});
});
});
});
https://
github.com/
jakobmattsson/
z-presentation/
blob/master/
promises-in-out/
1-naive.js
1
Note: without narration, this slide lacks a lot of
context. Open the file above and read the
commented version for the full story.
post('/blogs', {
name: 'My blog'
}, function(err, blog) {
! var entryData = [{
title: 'my first post',
body: 'Here is the text of my first post'
}, {
title: 'my second post',
body: 'I do not know what to write any more...'
}]
! async.forEach(entryData, function(entry, callback), {
post(concatUrl('blogs', blog.id, 'entries'), entry, callback);
}, function(err, entries) {
! var usernames = ['john doe', 'jane doe'];
! async.forEach(usernames, function(user, callback) {
post('/user', { name: user }, callback);
}, function(err, visitors) {
! var commentsData = [{
userId: visitor[0].id,
entryId: entries[0].id,
text: "well written dude"
}, {
userId: visitor[1].id,
entryId: entries[0].id,
text: "like it!"
}, {
userId: visitor[1].id,
entryId: entries[1].id,
text: "nah, crap"
}];
! async.forEach(commentsData, function(comment, callback) {
post('/comments', comment, callback);
}, function(err, comments) {
! get(concatUrl('blogs', blog.id), function(err, blogInfo) {
! assertEquals(blogInfo, {
name: 'My blog',
numberOfEntries: 2,
numberOfComments: 3
});
});
});
});
});
});
https://
github.com/
jakobmattsson/
z-presentation/
blob/master/
promises-in-out/
2-async.js
2
Note: without narration, this slide lacks a lot of
context. Open the file above and read the
commented version for the full story.
https://
github.com/
jakobmattsson/
z-presentation/
blob/master/
promises-in-out/
3-async-more-parallel.js
3
Note: without narration, this slide lacks a lot of
context. Open the file above and read the
commented version for the full story.
post('/blogs', {
name: 'My blog'
}, function(err, blog) {
! async.parallel([
function(callback) {
var entryData = [{
title: 'my first post',
body: 'Here is the text of my first post'
}, {
title: 'my second post',
body: 'I do not know what to write any more...'
}];
async.forEach(entryData, function(entry, callback), {
post(concatUrl('blogs', blog.id, 'entries'), entry, callback);
}, callback);
},
function(callback) {
var usernames = ['john doe', 'jane doe’];
async.forEach(usernames, function(user, callback) {
post('/user', { name: user }, callback);
}, callback);
}
], function(err, results) {
! var entries = results[0];
var visitors = results[1];
! var commentsData = [{
userId: visitors[0].id,
entryId: entries[0].id,
text: "well written dude"
}, {
userId: visitors[1].id,
entryId: entries[0].id,
text: "like it!"
}, {
userId: visitors[1].id,
entryId: entries[1].id,
text: "nah, crap"
}];
! async.forEach(commentsData, function(comment, callback) {
post('/comments', comment, callback);
}, function(err, comments) {
! get(concatUrl('blogs', blog.id), function(err, blogInfo) {
assertEquals(blogInfo, {
name: 'My blog',
numberOfEntries: 2,
numberOfComments: 3
});
});
});
});
});
post('/blogs', {
name: 'My blog'
}).then(function(blog) {
! var visitor1 = post('/user', {
name: 'john doe'
});
! var visitor2 = post('/user', {
name: 'jane doe'
});
! var entry1 = post(concatUrl('blogs', blog.id, 'entries'), {
title: 'my first post',
body: 'Here is the text of my first post'
});
! var entry2 = post(concatUrl('blogs', blog.id, 'entries'), {
title: 'my second post',
body: 'I do not know what to write any more...'
});
! var comment1 = all(entry1, visitor1).then(function(e1, v1) {
post('/comments', {
userId: v1.id,
entryId: e1.id,
text: "well written dude"
});
});
! var comment2 = all(entry1, visitor2).then(function(e1, v2) {
post('/comments', {
userId: v2.id,
entryId: e1.id,
text: "like it!"
});
});
! var comment3 = all(entry2, visitor2).then(function(e2, v2) {
post('/comments', {
userId: v2.id,
entryId: e2.id,
text: "nah, crap"
});
});
! all(comment1, comment2, comment3).then(function() {
get(concatUrl('blogs', blog.id)).then(function(blogInfo) {
assertEquals(blogInfo, {
name: 'My blog',
numberOfEntries: 2,
numberOfComments: 3
});
});
});
});
https://
github.com/
jakobmattsson/
z-presentation/
blob/master/
promises-in-out/
4-promises-convoluted.js
4
Note: without narration, this slide lacks a lot of
context. Open the file above and read the
commented version for the full story.
var blog = post('/blogs', {
name: 'My blog'
});
!var entry1 = post(concatUrl('blogs', blog.get('id'), 'entries'), {
title: 'my first post',
body: 'Here is the text of my first post'
});
!var entry2 = post(concatUrl('blogs', blog.get('id'), 'entries'), {
title: 'my second post',
body: 'I do not know what to write any more...'
});
!var visitor1 = post('/user', {
name: 'john doe'
});
!var visitor2 = post('/user', {
name: 'jane doe'
});
!var comment1 = post('/comments', {
userId: visitor1.get('id'),
entryId: entry1.get('id'),
text: "well written dude"
});
!var comment2 = post('/comments', {
userId: visitor2.get('id'),
entryId: entry1.get('id'),
text: "like it!"
});
!var comment3 = post('/comments', {
userId: visitor2.get('id'),
entryId: entry2.get('id'),
text: "nah, crap"
});
!var allComments = [comment1, comment2, comment2];
!var blogInfoUrl = concatUrl('blogs', blog.get('id'));
!var blogInfo = getAfter(blogInfoUrl, allComments);
!assertEquals(blogInfo, {
name: 'My blog',
numberOfEntries: 2,
numberOfComments: 3
});
https://
github.com/
jakobmattsson/
z-presentation/
blob/master/
promises-in-out/
5-promises-nice.js
5
Note: without narration, this slide lacks a lot of
context. Open the file above and read the
commented version for the full story.
1 Promises out: Always return promises -
not callback
2 Promises in: Functions should accept
promises as well as regular values
Three requirements
Awesome!
1 Promises out: Always return promises -
not callback
2 Promises in: Functions should accept
promises as well as regular values
3 Promises between: Augment promises as
you augment regular objects
Three requirements
Augmenting objects
is a sensitive topic
Extending prototypes
!
vs
!
wrapping objects
You’re writing Course of action
An app Do whatever you want
A library
Do not modify the

damn prototypes
Complimentary
decision matrix
Promises are already
wrapped objects
_(names)
.chain()
.unique()
.shuffle()
.first(3)
.value()
Chaining usually requires a
method to ”unwrap”
or repeated wrapping
u = _(names).unique()
s = _(u).shuffle()
f = _(s).first(3)
Promises already have a
well-defined way of
unwrapping.
_(names)
.unique()
.shuffle()
.first(3)
.then(function(values) {
// do stuff with values...
})
If underscore/lodash
wrapped promises
But they don’t
Enter
!
Z
1 Deep resolution: Resolve any kind of
object/array/promise/values/whatever
2 Make functions promise-friendly: Sync or
async doesn’t matter; will accept promises
3 Augmentation for promises: jQuery/
underscore/lodash-like extensions
What is Z?
Deep resolution
var data = {
userId: visitor1.get('id'),
entryId: entry1.get('id'),
text: 'well written dude'
};
!
Z(data).then(function(result) {
!
// result is now: {
// userId: 123,
// entryId: 456,
// text: 'well written dude'
// }
!
});
Takes any object
and resolves all
promises in it.
!
Like Q and Q.all,
but deep
1
Promise-friendly functions
var post = function(url, data, callback) {
// POSTs `data` to `url` and
// then invokes `callback`
};
!
post = Z.bindAsync(post);
!
var comment1 = post('/comments', {
userId: visitor1.get('id'),
entryId: entry1.get('id'),
text: 'well written dude'
});
bindAsync creates
a function that
takes promises as
arguments and
returns a promise.
2
Promise-friendly functions
var add = function(x, y) {
return x + y;
};
!
add = Z.bindSync(add);
!
var sum = add(v1.get('id'), e1.get('id'));
!
var comment1 = post('/comments', {
userId: visitor1.get('id'),
entryId: entry1.get('id'),
text: 'well written dude',
likes: sum
});
2
bindSync does that
same, for functions
that are not async
Augmentation for promises
var commentData = get('/comments/42');
!
var text = commentData.get('text');
!
var lowerCased = text.then(function(text) {
return text.toLowerCase();
});
3
Without
augmentation
every operation
has to be wrapped
in ”then”
Augmentation for promises
Z.mixin({
toLowerCase: function() {
return this.value.toLowerCase();
}
});
!
var commentData = get('/comments/42');
!
commentData.get('text').toLowerCase();
3
Z has mixin to
solve this
!
Note that Z is not
explicitly applied
to the promise
Augmentation for promises
Z.mixin(zUnderscore);
Z.mixin(zBuiltins);
!
var comment = get('/comments/42');
!
comment.get('text').toLowerCase().first(5);
3
There are prepared
packages to mixin
entire libraries
1 Promises out: Always return promises -
not callback
2 Promises in: Functions should accept
promises as well as regular values
3 Promises between: Augment promises as
you augment regular objects
Three requirements
Make async code
as straightforward
as sync code
Enough with
the madness
You don’t need a lib
to do these things
But please
www.jakobm.com @jakobmattsson
!
github.com/jakobmattsson/z-core
Testing web APIs
Simple and readable

Weitere ähnliche Inhalte

Was ist angesagt?

jQuery Proven Performance Tips & Tricks
jQuery Proven Performance Tips & TricksjQuery Proven Performance Tips & Tricks
jQuery Proven Performance Tips & TricksAddy Osmani
 
Deploying a Location-Aware Ember Application
Deploying a Location-Aware Ember ApplicationDeploying a Location-Aware Ember Application
Deploying a Location-Aware Ember ApplicationBen Limmer
 
Crafting Quality PHP Applications (PHPkonf 2018)
Crafting Quality PHP Applications (PHPkonf 2018)Crafting Quality PHP Applications (PHPkonf 2018)
Crafting Quality PHP Applications (PHPkonf 2018)James Titcumb
 
Maintainable JavaScript 2012
Maintainable JavaScript 2012Maintainable JavaScript 2012
Maintainable JavaScript 2012Nicholas Zakas
 
Crafting Quality PHP Applications (PHP Benelux 2018)
Crafting Quality PHP Applications (PHP Benelux 2018)Crafting Quality PHP Applications (PHP Benelux 2018)
Crafting Quality PHP Applications (PHP Benelux 2018)James Titcumb
 
Crafting Quality PHP Applications (Bucharest Tech Week 2017)
Crafting Quality PHP Applications (Bucharest Tech Week 2017)Crafting Quality PHP Applications (Bucharest Tech Week 2017)
Crafting Quality PHP Applications (Bucharest Tech Week 2017)James Titcumb
 
Crafting Quality PHP Applications (PHP Joburg Oct 2019)
Crafting Quality PHP Applications (PHP Joburg Oct 2019)Crafting Quality PHP Applications (PHP Joburg Oct 2019)
Crafting Quality PHP Applications (PHP Joburg Oct 2019)James Titcumb
 
Eugene Andruszczenko: jQuery
Eugene Andruszczenko: jQueryEugene Andruszczenko: jQuery
Eugene Andruszczenko: jQueryRefresh Events
 
Outside-in Development with Cucumber and Rspec
Outside-in Development with Cucumber and RspecOutside-in Development with Cucumber and Rspec
Outside-in Development with Cucumber and RspecJoseph Wilk
 
Dip Your Toes in the Sea of Security (ConFoo YVR 2017)
Dip Your Toes in the Sea of Security (ConFoo YVR 2017)Dip Your Toes in the Sea of Security (ConFoo YVR 2017)
Dip Your Toes in the Sea of Security (ConFoo YVR 2017)James Titcumb
 
Best practices for crafting high quality PHP apps (php[world] 2019)
Best practices for crafting high quality PHP apps (php[world] 2019)Best practices for crafting high quality PHP apps (php[world] 2019)
Best practices for crafting high quality PHP apps (php[world] 2019)James Titcumb
 
Rails for Beginners - Le Wagon
Rails for Beginners - Le WagonRails for Beginners - Le Wagon
Rails for Beginners - Le WagonAlex Benoit
 
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 modulesjerryorr
 
Building a Single Page Application using Ember.js ... for fun and profit
Building a Single Page Application using Ember.js ... for fun and profitBuilding a Single Page Application using Ember.js ... for fun and profit
Building a Single Page Application using Ember.js ... for fun and profitBen Limmer
 
Enabling agile devliery through enabling BDD in PHP projects
Enabling agile devliery through enabling BDD in PHP projectsEnabling agile devliery through enabling BDD in PHP projects
Enabling agile devliery through enabling BDD in PHP projectsKonstantin Kudryashov
 

Was ist angesagt? (20)

jQuery Proven Performance Tips & Tricks
jQuery Proven Performance Tips & TricksjQuery Proven Performance Tips & Tricks
jQuery Proven Performance Tips & Tricks
 
Deploying a Location-Aware Ember Application
Deploying a Location-Aware Ember ApplicationDeploying a Location-Aware Ember Application
Deploying a Location-Aware Ember Application
 
Crafting Quality PHP Applications (PHPkonf 2018)
Crafting Quality PHP Applications (PHPkonf 2018)Crafting Quality PHP Applications (PHPkonf 2018)
Crafting Quality PHP Applications (PHPkonf 2018)
 
Maintainable JavaScript 2012
Maintainable JavaScript 2012Maintainable JavaScript 2012
Maintainable JavaScript 2012
 
End-to-end testing with geb
End-to-end testing with gebEnd-to-end testing with geb
End-to-end testing with geb
 
Crafting Quality PHP Applications (PHP Benelux 2018)
Crafting Quality PHP Applications (PHP Benelux 2018)Crafting Quality PHP Applications (PHP Benelux 2018)
Crafting Quality PHP Applications (PHP Benelux 2018)
 
Crafting Quality PHP Applications (Bucharest Tech Week 2017)
Crafting Quality PHP Applications (Bucharest Tech Week 2017)Crafting Quality PHP Applications (Bucharest Tech Week 2017)
Crafting Quality PHP Applications (Bucharest Tech Week 2017)
 
Crafting Quality PHP Applications (PHP Joburg Oct 2019)
Crafting Quality PHP Applications (PHP Joburg Oct 2019)Crafting Quality PHP Applications (PHP Joburg Oct 2019)
Crafting Quality PHP Applications (PHP Joburg Oct 2019)
 
Step objects
Step objectsStep objects
Step objects
 
Eugene Andruszczenko: jQuery
Eugene Andruszczenko: jQueryEugene Andruszczenko: jQuery
Eugene Andruszczenko: jQuery
 
Outside-in Development with Cucumber and Rspec
Outside-in Development with Cucumber and RspecOutside-in Development with Cucumber and Rspec
Outside-in Development with Cucumber and Rspec
 
Dip Your Toes in the Sea of Security (ConFoo YVR 2017)
Dip Your Toes in the Sea of Security (ConFoo YVR 2017)Dip Your Toes in the Sea of Security (ConFoo YVR 2017)
Dip Your Toes in the Sea of Security (ConFoo YVR 2017)
 
Django Heresies
Django HeresiesDjango Heresies
Django Heresies
 
Best practices for crafting high quality PHP apps (php[world] 2019)
Best practices for crafting high quality PHP apps (php[world] 2019)Best practices for crafting high quality PHP apps (php[world] 2019)
Best practices for crafting high quality PHP apps (php[world] 2019)
 
Rails for Beginners - Le Wagon
Rails for Beginners - Le WagonRails for Beginners - Le Wagon
Rails for Beginners - Le Wagon
 
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
 
Building a Single Page Application using Ember.js ... for fun and profit
Building a Single Page Application using Ember.js ... for fun and profitBuilding a Single Page Application using Ember.js ... for fun and profit
Building a Single Page Application using Ember.js ... for fun and profit
 
Selenium bootcamp slides
Selenium bootcamp slides   Selenium bootcamp slides
Selenium bootcamp slides
 
Cucumber
CucumberCucumber
Cucumber
 
Enabling agile devliery through enabling BDD in PHP projects
Enabling agile devliery through enabling BDD in PHP projectsEnabling agile devliery through enabling BDD in PHP projects
Enabling agile devliery through enabling BDD in PHP projects
 

Andere mochten auch

How to survive on Magento platform
How to survive on Magento platformHow to survive on Magento platform
How to survive on Magento platformaheadWorks
 
Александр Анцыпов. REST: вывод традиционных систем на новый уровень
Александр Анцыпов. REST: вывод традиционных систем на новый уровеньАлександр Анцыпов. REST: вывод традиционных систем на новый уровень
Александр Анцыпов. REST: вывод традиционных систем на новый уровеньVolha Banadyseva
 
Андрей Светлов. Aiohttp
Андрей Светлов. AiohttpАндрей Светлов. Aiohttp
Андрей Светлов. AiohttpVolha Banadyseva
 
Magento performance
Magento performanceMagento performance
Magento performanceaheadWorks
 
Александр Белокрылов. Java 8: Create The Future
Александр Белокрылов. Java 8: Create The FutureАлександр Белокрылов. Java 8: Create The Future
Александр Белокрылов. Java 8: Create The FutureVolha Banadyseva
 
Writing extensions for Xcommerce
Writing extensions for XcommerceWriting extensions for Xcommerce
Writing extensions for XcommerceaheadWorks
 
В погоне за производительностью
В погоне за производительностьюВ погоне за производительностью
В погоне за производительностьюFDConf
 
Если у вас нету тестов...
Если у вас нету тестов...Если у вас нету тестов...
Если у вас нету тестов...FDConf
 
Migrate your React.js application from (m)Observable to Redux
Migrate your React.js application from (m)Observable to ReduxMigrate your React.js application from (m)Observable to Redux
Migrate your React.js application from (m)Observable to ReduxFDConf
 

Andere mochten auch (9)

How to survive on Magento platform
How to survive on Magento platformHow to survive on Magento platform
How to survive on Magento platform
 
Александр Анцыпов. REST: вывод традиционных систем на новый уровень
Александр Анцыпов. REST: вывод традиционных систем на новый уровеньАлександр Анцыпов. REST: вывод традиционных систем на новый уровень
Александр Анцыпов. REST: вывод традиционных систем на новый уровень
 
Андрей Светлов. Aiohttp
Андрей Светлов. AiohttpАндрей Светлов. Aiohttp
Андрей Светлов. Aiohttp
 
Magento performance
Magento performanceMagento performance
Magento performance
 
Александр Белокрылов. Java 8: Create The Future
Александр Белокрылов. Java 8: Create The FutureАлександр Белокрылов. Java 8: Create The Future
Александр Белокрылов. Java 8: Create The Future
 
Writing extensions for Xcommerce
Writing extensions for XcommerceWriting extensions for Xcommerce
Writing extensions for Xcommerce
 
В погоне за производительностью
В погоне за производительностьюВ погоне за производительностью
В погоне за производительностью
 
Если у вас нету тестов...
Если у вас нету тестов...Если у вас нету тестов...
Если у вас нету тестов...
 
Migrate your React.js application from (m)Observable to Redux
Migrate your React.js application from (m)Observable to ReduxMigrate your React.js application from (m)Observable to Redux
Migrate your React.js application from (m)Observable to Redux
 

Ähnlich wie Testing web APIs

Getting Answers to Your Testing Questions
Getting Answers to Your Testing QuestionsGetting Answers to Your Testing Questions
Getting Answers to Your Testing Questionsjasnow
 
Lect-5--JavaScript-Intro-12032024-105816am.pptx
Lect-5--JavaScript-Intro-12032024-105816am.pptxLect-5--JavaScript-Intro-12032024-105816am.pptx
Lect-5--JavaScript-Intro-12032024-105816am.pptxzainm7032
 
How to actually use promises - Jakob Mattsson, FishBrain
How to actually use promises - Jakob Mattsson, FishBrainHow to actually use promises - Jakob Mattsson, FishBrain
How to actually use promises - Jakob Mattsson, FishBrainCodemotion Tel Aviv
 
Controller Testing: You're Doing It Wrong
Controller Testing: You're Doing It WrongController Testing: You're Doing It Wrong
Controller Testing: You're Doing It Wrongjohnnygroundwork
 
JavaScript Interview Questions Part - 1.pdf
JavaScript Interview Questions Part - 1.pdfJavaScript Interview Questions Part - 1.pdf
JavaScript Interview Questions Part - 1.pdfkatarichallenge
 
Build a game with javascript (may 21 atlanta)
Build a game with javascript (may 21 atlanta)Build a game with javascript (may 21 atlanta)
Build a game with javascript (may 21 atlanta)Thinkful
 
Plugin Development @ WordCamp Norway 2014
Plugin Development @ WordCamp Norway 2014Plugin Development @ WordCamp Norway 2014
Plugin Development @ WordCamp Norway 2014Barry Kooij
 
Intro to javascript (6:19)
Intro to javascript (6:19)Intro to javascript (6:19)
Intro to javascript (6:19)Thinkful
 
JSON REST API for WordPress
JSON REST API for WordPressJSON REST API for WordPress
JSON REST API for WordPressTaylor Lovett
 
Building Better Web APIs with Rails
Building Better Web APIs with RailsBuilding Better Web APIs with Rails
Building Better Web APIs with RailsAll Things Open
 
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010singingfish
 
Thinkful - Intro to JavaScript
Thinkful - Intro to JavaScriptThinkful - Intro to JavaScript
Thinkful - Intro to JavaScriptTJ Stalcup
 
Why you should be using the shiny new C# 6.0 features now!
Why you should be using the shiny new C# 6.0 features now!Why you should be using the shiny new C# 6.0 features now!
Why you should be using the shiny new C# 6.0 features now!Eric Phan
 
Intro to JavaScript - Thinkful LA, June 2017
Intro to JavaScript - Thinkful LA, June 2017Intro to JavaScript - Thinkful LA, June 2017
Intro to JavaScript - Thinkful LA, June 2017Thinkful
 
Testing swagger contracts without contract based testing
Testing swagger contracts without contract based testingTesting swagger contracts without contract based testing
Testing swagger contracts without contract based testingАлексей Стягайло
 
Journey To The Front End World - Part3 - The Machine
Journey To The Front End World - Part3 - The MachineJourney To The Front End World - Part3 - The Machine
Journey To The Front End World - Part3 - The MachineIrfan Maulana
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsMike Subelsky
 

Ähnlich wie Testing web APIs (20)

Getting Answers to Your Testing Questions
Getting Answers to Your Testing QuestionsGetting Answers to Your Testing Questions
Getting Answers to Your Testing Questions
 
Lect-5--JavaScript-Intro-12032024-105816am.pptx
Lect-5--JavaScript-Intro-12032024-105816am.pptxLect-5--JavaScript-Intro-12032024-105816am.pptx
Lect-5--JavaScript-Intro-12032024-105816am.pptx
 
How to actually use promises - Jakob Mattsson, FishBrain
How to actually use promises - Jakob Mattsson, FishBrainHow to actually use promises - Jakob Mattsson, FishBrain
How to actually use promises - Jakob Mattsson, FishBrain
 
Controller Testing: You're Doing It Wrong
Controller Testing: You're Doing It WrongController Testing: You're Doing It Wrong
Controller Testing: You're Doing It Wrong
 
JavaScript Interview Questions Part - 1.pdf
JavaScript Interview Questions Part - 1.pdfJavaScript Interview Questions Part - 1.pdf
JavaScript Interview Questions Part - 1.pdf
 
Angular js
Angular jsAngular js
Angular js
 
Java script
Java scriptJava script
Java script
 
Build a game with javascript (may 21 atlanta)
Build a game with javascript (may 21 atlanta)Build a game with javascript (may 21 atlanta)
Build a game with javascript (may 21 atlanta)
 
Plugin Development @ WordCamp Norway 2014
Plugin Development @ WordCamp Norway 2014Plugin Development @ WordCamp Norway 2014
Plugin Development @ WordCamp Norway 2014
 
Intro to javascript (6:19)
Intro to javascript (6:19)Intro to javascript (6:19)
Intro to javascript (6:19)
 
JSON REST API for WordPress
JSON REST API for WordPressJSON REST API for WordPress
JSON REST API for WordPress
 
Building Better Web APIs with Rails
Building Better Web APIs with RailsBuilding Better Web APIs with Rails
Building Better Web APIs with Rails
 
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
 
Introdution to Node.js
Introdution to Node.jsIntrodution to Node.js
Introdution to Node.js
 
Thinkful - Intro to JavaScript
Thinkful - Intro to JavaScriptThinkful - Intro to JavaScript
Thinkful - Intro to JavaScript
 
Why you should be using the shiny new C# 6.0 features now!
Why you should be using the shiny new C# 6.0 features now!Why you should be using the shiny new C# 6.0 features now!
Why you should be using the shiny new C# 6.0 features now!
 
Intro to JavaScript - Thinkful LA, June 2017
Intro to JavaScript - Thinkful LA, June 2017Intro to JavaScript - Thinkful LA, June 2017
Intro to JavaScript - Thinkful LA, June 2017
 
Testing swagger contracts without contract based testing
Testing swagger contracts without contract based testingTesting swagger contracts without contract based testing
Testing swagger contracts without contract based testing
 
Journey To The Front End World - Part3 - The Machine
Journey To The Front End World - Part3 - The MachineJourney To The Front End World - Part3 - The Machine
Journey To The Front End World - Part3 - The Machine
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web Apps
 

Mehr von FDConf

Антон Киршанов - «Квант изменения. Реактивные реакции на React.
Антон Киршанов - «Квант изменения. Реактивные реакции на React.Антон Киршанов - «Квант изменения. Реактивные реакции на React.
Антон Киршанов - «Квант изменения. Реактивные реакции на React.FDConf
 
Игорь Еростенко - Создаем виртуальный тур
Игорь Еростенко - Создаем виртуальный турИгорь Еростенко - Создаем виртуальный тур
Игорь Еростенко - Создаем виртуальный турFDConf
 
Илья Климов - Reason: маргиналы против хайпа
Илья Климов - Reason: маргиналы против хайпаИлья Климов - Reason: маргиналы против хайпа
Илья Климов - Reason: маргиналы против хайпаFDConf
 
Максим Щепелин - Доставляя веб-контент в игру
Максим Щепелин - Доставляя веб-контент в игруМаксим Щепелин - Доставляя веб-контент в игру
Максим Щепелин - Доставляя веб-контент в игруFDConf
 
Александр Черноокий - Как правило "победитель получает все" работает и не раб...
Александр Черноокий - Как правило "победитель получает все" работает и не раб...Александр Черноокий - Как правило "победитель получает все" работает и не раб...
Александр Черноокий - Как правило "победитель получает все" работает и не раб...FDConf
 
Михаил Волчек - Что такое Цифровая мастерская?
Михаил Волчек - Что такое Цифровая мастерская?Михаил Волчек - Что такое Цифровая мастерская?
Михаил Волчек - Что такое Цифровая мастерская?FDConf
 
Radoslav Stankov - Handling GraphQL with React and Apollo
Radoslav Stankov - Handling GraphQL with React and ApolloRadoslav Stankov - Handling GraphQL with React and Apollo
Radoslav Stankov - Handling GraphQL with React and ApolloFDConf
 
Виктор Русакович - Выборы, выборы, все фреймворки… приторны
Виктор Русакович - Выборы, выборы, все фреймворки… приторныВиктор Русакович - Выборы, выборы, все фреймворки… приторны
Виктор Русакович - Выборы, выборы, все фреймворки… приторныFDConf
 
Slobodan Stojanovic - 8 1/2 things about serverless
Slobodan Stojanovic - 8 1/2 things about serverless Slobodan Stojanovic - 8 1/2 things about serverless
Slobodan Stojanovic - 8 1/2 things about serverless FDConf
 
Тимофей Лавренюк - Почему мне зашел PWA?
Тимофей Лавренюк - Почему мне зашел PWA?Тимофей Лавренюк - Почему мне зашел PWA?
Тимофей Лавренюк - Почему мне зашел PWA?FDConf
 
Dart: питание и сила для вашего проекта
Dart: питание и сила для вашего проектаDart: питание и сила для вашего проекта
Dart: питание и сила для вашего проектаFDConf
 
Scalable Angular 2 Application Architecture
Scalable Angular 2 Application ArchitectureScalable Angular 2 Application Architecture
Scalable Angular 2 Application ArchitectureFDConf
 
JavaScript: прошлое, настоящее и будущее.
JavaScript: прошлое, настоящее и будущее.JavaScript: прошлое, настоящее и будущее.
JavaScript: прошлое, настоящее и будущее.FDConf
 
CSSO — сжимаем CSS
CSSO — сжимаем CSSCSSO — сжимаем CSS
CSSO — сжимаем CSSFDConf
 
Redux. From twitter hype to production
Redux. From twitter hype to productionRedux. From twitter hype to production
Redux. From twitter hype to productionFDConf
 
Будь первым
Будь первымБудь первым
Будь первымFDConf
 
"Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native ""Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native "FDConf
 
"Пиринговый веб на JavaScript"
"Пиринговый веб на JavaScript""Пиринговый веб на JavaScript"
"Пиринговый веб на JavaScript"FDConf
 
«I knew there had to be a better way to build mobile app»​
«I knew there had to be a better way to build mobile app»​«I knew there had to be a better way to build mobile app»​
«I knew there had to be a better way to build mobile app»​FDConf
 
«Как перестать отлаживать асинхронные вызовы и начать жить»​
«Как перестать отлаживать асинхронные вызовы и начать жить»​«Как перестать отлаживать асинхронные вызовы и начать жить»​
«Как перестать отлаживать асинхронные вызовы и начать жить»​FDConf
 

Mehr von FDConf (20)

Антон Киршанов - «Квант изменения. Реактивные реакции на React.
Антон Киршанов - «Квант изменения. Реактивные реакции на React.Антон Киршанов - «Квант изменения. Реактивные реакции на React.
Антон Киршанов - «Квант изменения. Реактивные реакции на React.
 
Игорь Еростенко - Создаем виртуальный тур
Игорь Еростенко - Создаем виртуальный турИгорь Еростенко - Создаем виртуальный тур
Игорь Еростенко - Создаем виртуальный тур
 
Илья Климов - Reason: маргиналы против хайпа
Илья Климов - Reason: маргиналы против хайпаИлья Климов - Reason: маргиналы против хайпа
Илья Климов - Reason: маргиналы против хайпа
 
Максим Щепелин - Доставляя веб-контент в игру
Максим Щепелин - Доставляя веб-контент в игруМаксим Щепелин - Доставляя веб-контент в игру
Максим Щепелин - Доставляя веб-контент в игру
 
Александр Черноокий - Как правило "победитель получает все" работает и не раб...
Александр Черноокий - Как правило "победитель получает все" работает и не раб...Александр Черноокий - Как правило "победитель получает все" работает и не раб...
Александр Черноокий - Как правило "победитель получает все" работает и не раб...
 
Михаил Волчек - Что такое Цифровая мастерская?
Михаил Волчек - Что такое Цифровая мастерская?Михаил Волчек - Что такое Цифровая мастерская?
Михаил Волчек - Что такое Цифровая мастерская?
 
Radoslav Stankov - Handling GraphQL with React and Apollo
Radoslav Stankov - Handling GraphQL with React and ApolloRadoslav Stankov - Handling GraphQL with React and Apollo
Radoslav Stankov - Handling GraphQL with React and Apollo
 
Виктор Русакович - Выборы, выборы, все фреймворки… приторны
Виктор Русакович - Выборы, выборы, все фреймворки… приторныВиктор Русакович - Выборы, выборы, все фреймворки… приторны
Виктор Русакович - Выборы, выборы, все фреймворки… приторны
 
Slobodan Stojanovic - 8 1/2 things about serverless
Slobodan Stojanovic - 8 1/2 things about serverless Slobodan Stojanovic - 8 1/2 things about serverless
Slobodan Stojanovic - 8 1/2 things about serverless
 
Тимофей Лавренюк - Почему мне зашел PWA?
Тимофей Лавренюк - Почему мне зашел PWA?Тимофей Лавренюк - Почему мне зашел PWA?
Тимофей Лавренюк - Почему мне зашел PWA?
 
Dart: питание и сила для вашего проекта
Dart: питание и сила для вашего проектаDart: питание и сила для вашего проекта
Dart: питание и сила для вашего проекта
 
Scalable Angular 2 Application Architecture
Scalable Angular 2 Application ArchitectureScalable Angular 2 Application Architecture
Scalable Angular 2 Application Architecture
 
JavaScript: прошлое, настоящее и будущее.
JavaScript: прошлое, настоящее и будущее.JavaScript: прошлое, настоящее и будущее.
JavaScript: прошлое, настоящее и будущее.
 
CSSO — сжимаем CSS
CSSO — сжимаем CSSCSSO — сжимаем CSS
CSSO — сжимаем CSS
 
Redux. From twitter hype to production
Redux. From twitter hype to productionRedux. From twitter hype to production
Redux. From twitter hype to production
 
Будь первым
Будь первымБудь первым
Будь первым
 
"Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native ""Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native "
 
"Пиринговый веб на JavaScript"
"Пиринговый веб на JavaScript""Пиринговый веб на JavaScript"
"Пиринговый веб на JavaScript"
 
«I knew there had to be a better way to build mobile app»​
«I knew there had to be a better way to build mobile app»​«I knew there had to be a better way to build mobile app»​
«I knew there had to be a better way to build mobile app»​
 
«Как перестать отлаживать асинхронные вызовы и начать жить»​
«Как перестать отлаживать асинхронные вызовы и начать жить»​«Как перестать отлаживать асинхронные вызовы и начать жить»​
«Как перестать отлаживать асинхронные вызовы и начать жить»​
 

Kürzlich hochgeladen

08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Google AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGGoogle AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGSujit Pal
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 

Kürzlich hochgeladen (20)

08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Google AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGGoogle AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAG
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 

Testing web APIs

  • 1. jakobm.com @jakobmattsson I’m a coder first and foremost. I also help companies recruit coders, train coders and architect software. Sometimes I do technical due diligence and speak at conferences. ! Want more? Read my story or blog.
  • 2.
  • 3.
  • 5. FishBrain is the fastest, easiest way to log and share your fishing. ! Get instant updates from anglers on nearby lakes, rivers, and the coast.
  • 6. Testing web APIs Simple and readable
  • 7. Example - Testing a blog API • Create a blog • Create two blog entries • Create two users • Create a lotal of three comments from those users, on the two posts • Request the stats for the blog and check if the given number of entries and comments are correct
  • 8. post('/blogs', { name: 'My blog' }, function(err, blog) { ! post(concatUrl('blogs', blog.id, 'entries'), { title: 'my first post’, body: 'Here is the text of my first post' }, function(err, entry1) { ! post(concatUrl('blogs', blog.id, 'entries'), { title: 'my second post’, body: 'I do not know what to write any more...' }, function(err, entry2) { ! post('/user', { name: 'john doe’ }, function(err, visitor1) { ! post('/user', { name: 'jane doe' }, function(err, visitor2) { ! post('/comments', { userId: visitor1.id, entryId: entry1.id, text: "well written dude" }, function(err, comment1) { ! post('/comments', { userId: visitor2.id, entryId: entry1.id, text: "like it!" }, function(err, comment2) { ! post('/comments', { userId: visitor2.id, entryId: entry2.id, text: "nah, crap" }, function(err, comment3) { ! get(concatUrl('blogs', blog.id), function(err, blogInfo) { assertEquals(blogInfo, { name: 'My blog', numberOfEntries: 2, numberOfComments: 3 }); }); }); }); }); }); }); }); }); });
  • 9. *No, this is not a tutorial Promises 101*
  • 11. getJSON({ url: '/somewhere/over/the/rainbow', success: function(result) { // deal with it } }); rainbows.then(function(result) { // deal with it }); var rainbows = getJSON({ url: '/somewhere/over/the/rainbow' });
  • 12. getJSON({ url: '/somewhere/over/the/rainbow', success: function(result) { // deal with it } }); rainbows.then(function(result) { // deal with it }); var rainbows = getJSON({ url: '/somewhere/over/the/rainbow' }); f(rainbows);
  • 13. Why is that a good idea? • Loosen up the coupling • Superior error handling • Simplified async
  • 14. Why is that a good idea? • Loosen up the coupling • Superior error handling • Simplified async But in particular, it abstracts away the temporal dependencies in your program (or in this case, test)
  • 15. That’s enough 101 (even though people barely talk about the last - and most important - idea)
  • 17. Promises are not new http://github.com/kriskowal/q http://www.html5rocks.com/en/tutorials/es6/promises http://domenic.me/2012/10/14/youre-missing-the-point-of-promises http://www.promisejs.org https://github.com/bellbind/using-promise-q https://github.com/tildeio/rsvp.js https://github.com/cujojs/when
  • 19. They’ve even made it into ES6 Already implemented natively in Firefox 30Chrome 33
  • 20. So why are you not using them?
  • 21. So why are you not using them?
  • 22. How to draw an owl
  • 23. 1. Draw some circles How to draw an owl
  • 24. 1. Draw some circles 2.Draw the rest of the owl How to draw an owl
  • 25. We want to draw owls. ! Not circles.
  • 26. getJSON('story.json').then(function(story) { addHtmlToPage(story.heading); ! // Map our array of chapter urls to // an array of chapter json promises. // This makes sture they all download parallel. return story.chapterUrls.map(getJSON) .reduce(function(sequence, chapterPromise) { // Use reduce to chain the promises together, // adding content to the page for each chapter return sequence.then(function() { // Wait for everything in the sequence so far, // then wait for this chapter to arrive. return chapterPromise; }).then(function(chapter) { addHtmlToPage(chapter.html); }); }, Promise.resolve()); }).then(function() { addTextToPage('All done'); }).catch(function(err) { // catch any error that happened along the way addTextToPage("Argh, broken: " + err.message); }).then(function() { document.querySelector('.spinner').style.display = 'none'; }); As announced for ES6
  • 28. browser.init({browserName:'chrome'}, function() { browser.get("http://admc.io/wd/test-pages/guinea-pig.html", function() { browser.title(function(err, title) { title.should.include('WD'); browser.elementById('i am a link', function(err, el) { browser.clickElement(el, function() { browser.eval("window.location.href", function(err, href) { href.should.include('guinea-pig2'); browser.quit(); }); }); }); }); }); }); Node.js WebDriver Before promises
  • 29. browser .init({ browserName: 'chrome' }) .then(function() { return browser.get("http://admc.io/wd/test-pages/guinea-pig.html"); }) .then(function() { return browser.title(); }) .then(function(title) { title.should.include('WD'); return browser.elementById('i am a link'); }) .then(function(el) { return browser.clickElement(el); }) .then(function() { return browser.eval("window.location.href"); }) .then(function(href) { href.should.include('guinea-pig2'); }) .fin(function() { return browser.quit(); }) .done(); After promises
  • 31.
  • 32.
  • 33. These examples are just a different way of doing async. ! It’s still uncomfortable. It’s still circles!
  • 34. The point of promises:
  • 35. ! Make async code as straightforward as sync code The point of promises:
  • 36. 1 Promises out: Always return promises - not callback 2 Promises in: Functions should accept promises as well as regular values 3 Promises between: Augment promises as you augment regular objects Three requirements
  • 38. Example - Testing a blog API • Create a blog • Create two blog entries • Create some users • Create some comments from those users, on the two posts • Request the stats for the blog and check if the given number of entries and comments are correct
  • 39. post('/blogs', { name: 'My blog' }, function(err, blog) { ! post(concatUrl('blogs', blog.id, 'entries'), { title: 'my first post’, body: 'Here is the text of my first post' }, function(err, entry1) { ! post(concatUrl('blogs', blog.id, 'entries'), { title: 'my second post’, body: 'I do not know what to write any more...' }, function(err, entry2) { ! post('/user', { name: 'john doe’ }, function(err, visitor1) { ! post('/user', { name: 'jane doe' }, function(err, visitor2) { ! post('/comments', { userId: visitor1.id, entryId: entry1.id, text: "well written dude" }, function(err, comment1) { ! post('/comments', { userId: visitor2.id, entryId: entry1.id, text: "like it!" }, function(err, comment2) { ! post('/comments', { userId: visitor2.id, entryId: entry2.id, text: "nah, crap" }, function(err, comment3) { ! get(concatUrl('blogs', blog.id), function(err, blogInfo) { assertEquals(blogInfo, { name: 'My blog', numberOfEntries: 2, numberOfComments: 3 }); }); }); }); }); }); }); }); }); }); https:// github.com/ jakobmattsson/ z-presentation/ blob/master/ promises-in-out/ 1-naive.js 1 Note: without narration, this slide lacks a lot of context. Open the file above and read the commented version for the full story.
  • 40. post('/blogs', { name: 'My blog' }, function(err, blog) { ! var entryData = [{ title: 'my first post', body: 'Here is the text of my first post' }, { title: 'my second post', body: 'I do not know what to write any more...' }] ! async.forEach(entryData, function(entry, callback), { post(concatUrl('blogs', blog.id, 'entries'), entry, callback); }, function(err, entries) { ! var usernames = ['john doe', 'jane doe']; ! async.forEach(usernames, function(user, callback) { post('/user', { name: user }, callback); }, function(err, visitors) { ! var commentsData = [{ userId: visitor[0].id, entryId: entries[0].id, text: "well written dude" }, { userId: visitor[1].id, entryId: entries[0].id, text: "like it!" }, { userId: visitor[1].id, entryId: entries[1].id, text: "nah, crap" }]; ! async.forEach(commentsData, function(comment, callback) { post('/comments', comment, callback); }, function(err, comments) { ! get(concatUrl('blogs', blog.id), function(err, blogInfo) { ! assertEquals(blogInfo, { name: 'My blog', numberOfEntries: 2, numberOfComments: 3 }); }); }); }); }); }); https:// github.com/ jakobmattsson/ z-presentation/ blob/master/ promises-in-out/ 2-async.js 2 Note: without narration, this slide lacks a lot of context. Open the file above and read the commented version for the full story.
  • 41. https:// github.com/ jakobmattsson/ z-presentation/ blob/master/ promises-in-out/ 3-async-more-parallel.js 3 Note: without narration, this slide lacks a lot of context. Open the file above and read the commented version for the full story. post('/blogs', { name: 'My blog' }, function(err, blog) { ! async.parallel([ function(callback) { var entryData = [{ title: 'my first post', body: 'Here is the text of my first post' }, { title: 'my second post', body: 'I do not know what to write any more...' }]; async.forEach(entryData, function(entry, callback), { post(concatUrl('blogs', blog.id, 'entries'), entry, callback); }, callback); }, function(callback) { var usernames = ['john doe', 'jane doe’]; async.forEach(usernames, function(user, callback) { post('/user', { name: user }, callback); }, callback); } ], function(err, results) { ! var entries = results[0]; var visitors = results[1]; ! var commentsData = [{ userId: visitors[0].id, entryId: entries[0].id, text: "well written dude" }, { userId: visitors[1].id, entryId: entries[0].id, text: "like it!" }, { userId: visitors[1].id, entryId: entries[1].id, text: "nah, crap" }]; ! async.forEach(commentsData, function(comment, callback) { post('/comments', comment, callback); }, function(err, comments) { ! get(concatUrl('blogs', blog.id), function(err, blogInfo) { assertEquals(blogInfo, { name: 'My blog', numberOfEntries: 2, numberOfComments: 3 }); }); }); }); });
  • 42. post('/blogs', { name: 'My blog' }).then(function(blog) { ! var visitor1 = post('/user', { name: 'john doe' }); ! var visitor2 = post('/user', { name: 'jane doe' }); ! var entry1 = post(concatUrl('blogs', blog.id, 'entries'), { title: 'my first post', body: 'Here is the text of my first post' }); ! var entry2 = post(concatUrl('blogs', blog.id, 'entries'), { title: 'my second post', body: 'I do not know what to write any more...' }); ! var comment1 = all(entry1, visitor1).then(function(e1, v1) { post('/comments', { userId: v1.id, entryId: e1.id, text: "well written dude" }); }); ! var comment2 = all(entry1, visitor2).then(function(e1, v2) { post('/comments', { userId: v2.id, entryId: e1.id, text: "like it!" }); }); ! var comment3 = all(entry2, visitor2).then(function(e2, v2) { post('/comments', { userId: v2.id, entryId: e2.id, text: "nah, crap" }); }); ! all(comment1, comment2, comment3).then(function() { get(concatUrl('blogs', blog.id)).then(function(blogInfo) { assertEquals(blogInfo, { name: 'My blog', numberOfEntries: 2, numberOfComments: 3 }); }); }); }); https:// github.com/ jakobmattsson/ z-presentation/ blob/master/ promises-in-out/ 4-promises-convoluted.js 4 Note: without narration, this slide lacks a lot of context. Open the file above and read the commented version for the full story.
  • 43. var blog = post('/blogs', { name: 'My blog' }); !var entry1 = post(concatUrl('blogs', blog.get('id'), 'entries'), { title: 'my first post', body: 'Here is the text of my first post' }); !var entry2 = post(concatUrl('blogs', blog.get('id'), 'entries'), { title: 'my second post', body: 'I do not know what to write any more...' }); !var visitor1 = post('/user', { name: 'john doe' }); !var visitor2 = post('/user', { name: 'jane doe' }); !var comment1 = post('/comments', { userId: visitor1.get('id'), entryId: entry1.get('id'), text: "well written dude" }); !var comment2 = post('/comments', { userId: visitor2.get('id'), entryId: entry1.get('id'), text: "like it!" }); !var comment3 = post('/comments', { userId: visitor2.get('id'), entryId: entry2.get('id'), text: "nah, crap" }); !var allComments = [comment1, comment2, comment2]; !var blogInfoUrl = concatUrl('blogs', blog.get('id')); !var blogInfo = getAfter(blogInfoUrl, allComments); !assertEquals(blogInfo, { name: 'My blog', numberOfEntries: 2, numberOfComments: 3 }); https:// github.com/ jakobmattsson/ z-presentation/ blob/master/ promises-in-out/ 5-promises-nice.js 5 Note: without narration, this slide lacks a lot of context. Open the file above and read the commented version for the full story.
  • 44.
  • 45. 1 Promises out: Always return promises - not callback 2 Promises in: Functions should accept promises as well as regular values Three requirements
  • 47. 1 Promises out: Always return promises - not callback 2 Promises in: Functions should accept promises as well as regular values 3 Promises between: Augment promises as you augment regular objects Three requirements
  • 48. Augmenting objects is a sensitive topic
  • 50. You’re writing Course of action An app Do whatever you want A library Do not modify the
 damn prototypes Complimentary decision matrix
  • 51.
  • 53. _(names) .chain() .unique() .shuffle() .first(3) .value() Chaining usually requires a method to ”unwrap” or repeated wrapping u = _(names).unique() s = _(u).shuffle() f = _(s).first(3)
  • 54. Promises already have a well-defined way of unwrapping.
  • 55. _(names) .unique() .shuffle() .first(3) .then(function(values) { // do stuff with values... }) If underscore/lodash wrapped promises
  • 58. 1 Deep resolution: Resolve any kind of object/array/promise/values/whatever 2 Make functions promise-friendly: Sync or async doesn’t matter; will accept promises 3 Augmentation for promises: jQuery/ underscore/lodash-like extensions What is Z?
  • 59. Deep resolution var data = { userId: visitor1.get('id'), entryId: entry1.get('id'), text: 'well written dude' }; ! Z(data).then(function(result) { ! // result is now: { // userId: 123, // entryId: 456, // text: 'well written dude' // } ! }); Takes any object and resolves all promises in it. ! Like Q and Q.all, but deep 1
  • 60. Promise-friendly functions var post = function(url, data, callback) { // POSTs `data` to `url` and // then invokes `callback` }; ! post = Z.bindAsync(post); ! var comment1 = post('/comments', { userId: visitor1.get('id'), entryId: entry1.get('id'), text: 'well written dude' }); bindAsync creates a function that takes promises as arguments and returns a promise. 2
  • 61. Promise-friendly functions var add = function(x, y) { return x + y; }; ! add = Z.bindSync(add); ! var sum = add(v1.get('id'), e1.get('id')); ! var comment1 = post('/comments', { userId: visitor1.get('id'), entryId: entry1.get('id'), text: 'well written dude', likes: sum }); 2 bindSync does that same, for functions that are not async
  • 62. Augmentation for promises var commentData = get('/comments/42'); ! var text = commentData.get('text'); ! var lowerCased = text.then(function(text) { return text.toLowerCase(); }); 3 Without augmentation every operation has to be wrapped in ”then”
  • 63.
  • 64. Augmentation for promises Z.mixin({ toLowerCase: function() { return this.value.toLowerCase(); } }); ! var commentData = get('/comments/42'); ! commentData.get('text').toLowerCase(); 3 Z has mixin to solve this ! Note that Z is not explicitly applied to the promise
  • 65. Augmentation for promises Z.mixin(zUnderscore); Z.mixin(zBuiltins); ! var comment = get('/comments/42'); ! comment.get('text').toLowerCase().first(5); 3 There are prepared packages to mixin entire libraries
  • 66. 1 Promises out: Always return promises - not callback 2 Promises in: Functions should accept promises as well as regular values 3 Promises between: Augment promises as you augment regular objects Three requirements
  • 67. Make async code as straightforward as sync code Enough with the madness
  • 68. You don’t need a lib to do these things
  • 70.