var Me = { }; • Adam Hawkins • @adman65 • https://github.com/twinturbo • https://speakerdeck.com/u/twinturbo • Lead Code Monkey at Radium • Primarily Ruby guy, now focused on JS & Ember
Our Javascript Universe 1. Figure out how to split code into multiple files and deliver it as a single file 2. Do #1 while using Coffeescript, SCSS, and friends 3. Do #1 and #2 while being able to hit Refresh in the browser 4. Do #1, #2 and #3 while supporting different environments (dev, test, production, staging) 5. Do #1, #2, #3, and #4 while doing TDD 6. Do all of the above without creating an HTML files 7. Think of all the tools you need to do any of these...
That’s Quick Universe • New skeleton generated for us • Born from enterprise Ember requirements, but not framework specific • Integration and unit tests ready • jQuery, Handlebars, Qunit, and Sinon preloaded • Let’s build something
# test/integration/hello_test.coffee # straight up javascript - runs in any browser test "the app says hello", -> # Direct access to app code Todos.reset() Todos.userName = 'Adam' Todos.boot() assertEqual $("hello-world").text, "Adam"
Wait ... How? • CasperJS + PhantomJS + a bunch of h4x • Make your app available • Inject any test env specific code • Yes that is a full stack integration test • Great, it fails. Let’s keep going
// app.coffee - loads all the code Todos = Ember.Application.create({ VERSION: '1.0', storeNamespace: 'todos-emberjs', }) require 'todos/router' // app/javascripts/router.js|coffee require 'todos/models' // app/javascripts/models.js|coffee require 'todos/controllers' // you get require 'todos/views' // the point require 'todos/templates' // by now
That’s Not Vanilla JS • Minispade to require files • Module names generated from file names • Can be Coffeescript or Javascript • All files compiled into a single application.js • Let’s what our app looks like...
$ cd todos $ iridium server >> Thin web server (v1.4.1 codename Chromeo) >> Maximum connections set to 1024 >> Listening on 0.0.0.0:9292, CTRL+C to stop ... now hit Refresh
• We haven’t written any HTML • We haven’t needed to configure how load our code • We’ve run a full stack integration test without any configuration • ... But we have no functionality So Far...
# test/models/todo_test.coffee test "should default to not done", -> equal Models.todo.get('isDone'), false, "todo is not done" test "should set todo title", -> Models.todo.set 'title', "A todo" equal Models.todo.get('title'), "A todo", "todo title is set" test "should be able to signify isdone", -> Models.todo.set 'isDone', true ok Models.todo.get('isDone'), "Todo is done"
$ be iridium test test/models/todo_test.coffee Run options: --seed 14903 # Running Tests: EEE 3 Test(s), 3 Assertion(s), 0 Passed, 3 Error(s), 3 Failure(s) should default to not done TypeError: 'undefined' is not an object (evaluating 'Models.todo.get') # Backtrace /Users/adam/radium/iridium_tests/todos/test/support/qunit.js:340 /unit/models/todo_test.coffee:17 /unit/models/todo_test.coffee:29 should set todo title TypeError: 'undefined' is not an object (evaluating 'Models.todo.set') # Backtrace /Users/adam/radium/iridium_tests/todos/test/support/qunit.js:340 /unit/models/todo_test.coffee:22 /unit/models/todo_test.coffee:29 should be able to complete TypeError: 'undefined' is not an object (evaluating 'Models.todo.set') # Backtrace /Users/adam/radium/iridium_tests/todos/test/support/qunit.js:340 /unit/models/todo_test.coffee:27 /unit/models/todo_test.coffee:29
1. Ensure we have the correct code is there 2. Make an HTML file 3. Add a tag for QUnit<br/>4. Write <script> tags for support files<br/>5. Add a <script> tag for our test(s)<br/>6. Opens the HTML file using a browser<br/>7. Verify results<br/>It’s All the Stuff You<br/>Used to Do<br/>
Headless with PhantomJS • Open your app with your app code loaded • Inject test framework • Inject support code • Inject tests in Coffeescript or JS • Run a single test file • Repeat for all test files
Integrated Test Runner • Execute individual tests from the CLI • Unified runner for integration and unit tests • QUnit by default, Jasmine support possible • File in test/support/**/*.{js,coffee} automatically loaded for you • Report test results in real time • Individual test files completely isolated
Rake::Pipeline.build input "app" output "site" match "javascripts/**/*.coffee" do coffeescript end match "stylesheets/**/*.scss" do scss end match "**/*.js" do concat "application.js" uglify if production? end match "**/*.css" do concat "application.css" yui_css if production? end end
Iridium - Architecture • Convention over Configuration • Rake::Pipeline to compile, compress, and minify all application files into a single static directory • Test runner built on top of PhantomJS and CasperJS • Served through a custom middleware stack ending with Rack::Directory in development and production ... or • Serve with any language or webserver (Apache/ Nginx) in production
Fun Facts • Generates an HTML5 cache manifest • Works with Gaurd (modify a file, run its tests) • $ iridium lint • Proxies available to get around CORS or hide authentication tokens from Javascript • Use your own Assetfile if you like • i18n support built in • Automatically caches assets in production