Upload
others
View
6
Download
0
Embed Size (px)
Citation preview
NouryBouraqadi&DaveMasonhttp://pharojs.org
Tu to r i a l Pharo-Based TDD for Javascript Apps
RunonJavascript+
DevelopinPharo=
Tools+
Framework=
MITLicense
Why
• DevelopinSmalltalkallthetimeJ
• Portability
• Front-end/standalone
• ReuseexistingJSlibraries
• Run-timeSpeed
?
Javascript0% 100%
Development Production
100% Pharo 0%
DevelopinPharo,RunonJavascript
Javascript0% 100%
Smalltalkclasses
100% Pharo 0%
DevelopinPharo,RunonJavascript
Setofclasses+entrypointclass
Javascript0% 100%
ConvertSmalltalktoJS
100% Pharo 0%
DevelopinPharo,RunonJavascript
Onlyclassesreachablefromthe
entrypointclass
1.WriteTests
3.ExporttoJS2.Passthetests
Lifecyclewith
Javascript0% 100%
100% Pharo 0%
CaseStudy:TDDofaPhysicsSimulation
• ReuseanexistingJSLibrary• Testinghybridapp=Pharo+Javascript• LinkPharocodetoJSobjectsincludingDOM• Pushingtoproduction
Backlog
• Atstartup3bodiesè 1floorè 2fallingrectangles
• "Addxxx"buttonsèAddsabody
• "Reset"buttonèRemovesallbodies
WriteTests100%Pharo&0%JS
PjWebAppTestCasesubclass:#PhysicsSimTestinstanceVariableNames:''classVariableNames:''package:'ESUG2018'
WriteTests100%Pharo&0%JS
PjWebAppTestCasesubclass:#PhysicsSimTestinstanceVariableNames:''classVariableNames:''package:'ESUG2018'
Appshouldrunonawebbrowser
RunningtheTests~50%Pharo&~50%JS
app
Controller
engine
RunningtheTests~50%Pharo&~50%JS
PhysicsSimTest>>testAppInitialSetupselfassert:appbodiessizeequals:3.
Body1JSObject
Body2JSObject
Body3JSObject
RunningtheTests~50%Pharo&~50%JS
PhysicsSimTest>>testAppInitialSetupselfassert:appbodiessizeequals:3.
InstanceoftheentrypointclassPharoObject
RunningtheTests~50%Pharo&~50%JS
Missingentrypointclass
appClasssubclassResponsibility
DefiningtheEntryPointClass
PjFileBasedWebAppsubclass:#PhysicsSiminstanceVariableNames:'engine'classVariableNames:''package:'ESUG2018'
WerelyonanexternalHTMLfile
TestReferencesEntryPointClass
PhysicsSimTestclass>>appClass^PhysicsSim
Entrypointclass
TestRequestsAppFolder
TestRequestsAppFolder
FolderwhereHTML+otherfiles
arelocated
HTMLFile=App'sView
...<buttonid="resetButton"class="green">Reset</button><divid="simulationView"></div>...<scriptsrc="js/matter.js"></script><scriptsrc="index.js"></script>...
Third-partyJSLibrary
HTMLFile=App'sView
...<buttonid="resetButton"class="green">Reset</button><divid="simulationView"></div>...<scriptsrc="js/matter.js"></script><scriptsrc="js/index.js"></script>...
LinktoJSCodeGeneratedby
PharoJS
HTMLFile=App'sView
...<buttonid="resetButton"class="green">Reset</button><divid="simulationView"></div>...<scriptsrc="js/matter.js"></script><scriptsrc="js/index.js"></script>...
NoBehavior!
HTMLFile=App'sView
...<buttonid="resetButton"class="green">Reset</button><divid="simulationView"></div>...<scriptsrc="js/matter.js"></script><scriptsrc="js/index.js"></script>...
NoBehavior!
ID=toattachPharocode
RerunTests
PharoJSOpensHTMLfileinawebbrowser
RerunTests
PharoJSOpensHTMLfileinawebbrowser
NoSimulation!
RerunTests
FixingtheApp
PhysicsSim>>initializesuperinitialize.selfcreateAndStartEngine.selfsetupAndStartRendering.
PhysicsSim>>bodies^engineworldbodies
JSDoc/Examples PharoCode
FixingtheApp
PhysicsSim>>matterJsRoot^windowMatter
PhysicsSim>>createAndStartEngine|runner|engine:=selfmatterJsRootEnginecreate.runner:=selfmatterJsRootRunnercreate.selfmatterJsRootRunnerrun:runnerwith:engine
ProxytoJavascriptglobal
FixingtheApp
PhysicsSim>>matterJsRoot^windowMatter
PhysicsSim>>createAndStartEngine|runner|engine:=selfmatterJsRootEnginecreate.runner:=selfmatterJsRootRunnercreate.selfmatterJsRootRunnerrun:runnerwith:engine
PharoJSgeneratedaccessortoJSobjectproperty
FixingtheApp
PhysicsSim>>matterJsRoot^windowMatter
PhysicsSim>>createAndStartEngine|runner|engine:=selfmatterJsRootEnginecreate.runner:=selfmatterJsRootRunnercreate.selfmatterJsRootRunnerrun:runnerwith:engine
CallingJSmethodcreate()
FixingtheApp
PhysicsSim>>matterJsRoot^windowMatter
PhysicsSim>>createAndStartEngine|runner|engine:=selfmatterJsRootEnginecreate.runner:=selfmatterJsRootRunnercreate.selfmatterJsRootRunnerrun:runnerwith:engine
CallingJSmethodrun(runner,engine)
FixingtheAppPhysicsSim>>setupAndStartRendering|rendersimulationView|simulationView:=selfelementAt:#simulationView.render:=selfmatterJsRootRendercreate: {#element->simulationView. #engine->engine. #options->{#width->800. #height->600. #wireframes->false. #background->'transparent'}}asJsObject.
selfmatterJsRootRenderrun:render
FixingtheAppPhysicsSim>>setupAndStartRendering|rendersimulationView|simulationView:=selfelementAt:#simulationView.render:=selfmatterJsRootRendercreate: {#element->simulationView. #engine->engine. #options->{#width->800. #height->600. #wireframes->false. #background->'transparent'}}asJsObject.
selfmatterJsRootRenderrun:render
FindstheDOMelementwithID"SimulationView"
HTML
...<divid="simulationView"></div>...
FixingtheAppPhysicsSim>>setupAndStartRendering|rendersimulationView|simulationView:=selfelementAt:#simulationView.render:=selfmatterJsRootRendercreate: {#element->simulationView. #engine->engine. #options->{#width->800. #height->600. #wireframes->false. #background->'transparent'}}asJsObject.
selfmatterJsRootRenderrun:render
CreateaJSObjectfromaPharoDictionary
DefiningLiteralJSObjectsinPharo
{#element->simulationView.#engine->engine.#options->{#width->800.#height->600.#wireframes->false.#background->'transparent'}
}asJsObject.
JSDoc/Examples PharoCode
{element:simulationView.engine:engine.options:{width:800.height:600.wireframes:false.background:'transparent'}
}
Javascriptcode Pharoequivalent
RerunTests
FixingtheApp
PhysicsSim>>initializesuperinitialize.selfcreateAndStartEngine.selfsetupAndStartRendering.selfaddInitialBodies
Bodies.rectangle(400,610,810,60,{isStatic:true});
CreatingMatterJSBodies
selfmatterJsRootBodiesrectangle:400y:610width:810height:60options:{ #isStatic->true}asJsObject.
JSDoc/Examples PharoCode
Javascriptcode Pharoequivalent
1stTestPasses!
Morefeatures=ButtonHandling
Reset=DeleteMobileBodies
HTMLIDforLinkingwithPharo
HTML...<buttonid="resetButton">Reset</button>...
WriteTestsforResetButton
PhysicsSimTest>>testResetDeleteMobileBodiesOnlyselfclickElementById:#resetButton.selfassert:appbodiessizeequals:1.
HTML...<buttonid="resetButton">Reset</button>...
WriteTestsforResetButton
PhysicsSimTest>>testResetDeleteMobileBodiesOnlyselfclickElementById:#resetButton.selfassert:appbodiessizeequals:1.
HTML...<buttonid="resetButton">Reset</button>...
PharotriggerseventonDOMobject!
TestFails
AddBehaviortoHTMLButton
PhysicsSim>>initialize...selfonClick:#resetButton do:[selfmatterJsRootWorld clear:engineworld keepStatic:true]
AddBehaviortoHTMLButton
PhysicsSim>>initialize...selfonClick:#resetButton do:[selfmatterJsRootWorld clear:engineworld keepStatic:true]
HTMLID
AddBehaviortoHTMLButton
PhysicsSim>>initialize...selfonClick:#resetButton do:[selfmatterJsRootWorld clear:engineworld keepStatic:true]
PharoBlockCalling
MatterJSLibrary
AddBehaviortoHTMLButton
ValuePharoBlock
ClickonHTMLButton
Lifecyclewith
Javascript0% 100%
100% Pharo 0%
3.ExporttoJS
1.WriteTests2.Passthetests
ExportAppforProduction100%Javascript
ExportAppforProduction100%Javascript
ExportAppforProduction100%Javascript
ExportedJSfile
ExportedJSfile
...<scriptsrc="js/matter.js"></script><scriptsrc="js/index.js"></script>...
http://pharojs.org/Demo/MatterJsDemo/index.html
BeyondResearch!
OpenSourcefortheRealWorld
PharoTradition!
nootrix.com
Farmers Market
nootrix.com
GPSNavigation
ZoomableMap
UpdateMarkers
WhatNext?
• Bettersupportformobileapps• MigratetoPharo7
• ImproveCodeExtraction
• Middlewareforhybridapps
Thisafternoon!
LearnmoreaboutPharoJS• Web:http://pharojs.org– FAQ+...– ThanksESUGforthesupport
• Slack:https://pharojs.slack.com/– Discussions
• Twitter:https://twitter.com/pharojs– News– SubscriptiontoPharoJSSlack
NouryBouraqadi&DaveMason
DevelopinPharoRunonJavascript
http://pharojs.org