Your team has chosen to build the Input Blade. Without it nobody can enter any information into the application.
The Input Blade should have the following functionality:
textarea
button
that lets a user send information to other usersYou already have the application within the BladeRunnerJS installation. Within the root of the application directory you'll see a blades
sub-directory. This is where blades are to be created.
From the BladeRunnerJS sdk
directory run the following command to create a Blade:
./brjs create-blade modularapp default input
You've just scaffolded your first Blade. You can find the Blade skeleton in
apps/modularapp/blades/input
.
You can find out more about what's just been created in the Create a Blade docs.
Start the BRJS development server by running the following command from the sdk
directory:
./brjs serve
Now navigate to http://localhost:7070/modularapp/default/input/workbench/
to see your amazing Blade.
Feel free to take a look around the Blade assets to see how the code is structured and familiarise yourself with where things are.
Let's update the view to have the elements we need for our required functionality.
Open up the blades/input/resources/html/view.html
file and make it look as follows:
<section class="chat-input" id="modularapp.input.view-template">
<textarea class="chat-input-message"
placeholder="type a message"></textarea>
<button class="chat-input-send-btn">Send</button>
</section>
Reload the Workbench to make sure this looks okay.
Now, let's add some styling. Update blades/input/themes/standard/style.css
as follows:
/* Input Blade containing element */
.chat-input {
position: relative;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
/* push textarea in for button */
padding-right: 80px;
}
.chat-input .chat-input-message,
.chat-input .chat-input-send-btn {
height: 60px;
}
/* textarea */
.chat-input .chat-input-message {
display: block;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 100%;
}
/* button */
.chat-input .chat-input-send-btn {
position: absolute;
top: 0;
right: 0;
width: 75px;
text-align: center;
}
How does the Blade look in the Workbench now?
For this workshop we're using KnockoutJS as our data-binding solution. Knockout uses View Models that are logical representations of the views. A purist opinions of views is that that there should be no business logic in a View Model, but we're building a reasonably simple Blade (but feel free to refactor afterwards).
You can find the class definition for the Input View Model in blades/input/src/InputViewModel.js
;
yeah, sorry about the folder structure!
Update the InputViewModel
definition to look as follows:
'use strict';
var ko = require( 'ko' );
var Log = require( 'fell' ).Log;
function InputViewModel() {
this.message = ko.observable( '' );
}
InputViewModel.prototype.buttonClicked = function() {
return true;
};
module.exports = InputViewModel;
You'll notice that the tooling supports Node.js-style require( 'module' )
calls
and the functionality that the file exposes is determined via assignment to module.exports
.
Enough hand-holding! Time for some real exercises:
In order to do this you'll need to update the textarea
in the view definition
(view.html
) with an appropriate data-bind
property.
textarea
you'll need to click
the button or click out of the element.value
of the textarea
element so use the value
Knockout
binding.If you've not used KnockoutJS before or you just want to check your solution here it is:
<section class="chat-input" id="modularapp.input.view-template">
<textarea class="chat-input-message"
placeholder="type a message"
data-bind="value: message"></textarea>
<button class="chat-input-send-btn">Send</button>
</section>
You'll also need to use data-bind
for this.
Also, when the button is clicked take the value from the message
property and log it
to the console using Log.info( <your-log-message> )
. This will let you check that
the data binding is working as you expect it.
<section class="chat-input" id="modularapp.input.view-template">
<textarea class="chat-input-message"
placeholder="type a message"
data-bind="value: message"></textarea>
<button class="chat-input-send-btn"
data-bind="click:buttonClicked">Send</button>
</section>
You'll remember that one of the requirements was to only send the message to other
users if there was some text. So, check that the users has actually entered something.
The return value from the buttonClicked
function should then reflect that validity;
do this by returning true
if the message is valid and false
if it's invalid.
We'll be testing this shortly.
Here's the basics of what you need to do. Now just implement the messageValid
function.
InputViewModel.prototype.buttonClicked = function() {
var message = this.message();
var valid = messageValid( message );
Log.info( 'sent message? {0}', valid );
return valid;
};
function messageValid( message ) {
// TODO: implement
}
A key part of building a quality maintainable application is that it's tested. So, let's write a test that checks the default message should be blank.
Navigate to /blades/input/test-unit/tests
and open InputViewModelTest.js
.
It should look as follows:
var InputViewModelTest = TestCase( 'InputViewModelTest' );
var InputViewModel = require( 'modularapp/input/InputViewModel' );
InputViewModelTest.prototype.testSomething = function() {
var model = new InputViewModel();
assertEquals( 'Welcome to your new Blade.', model.welcomeMessage() );
};
There are lots of testing tools available. BladeRunnerJS comes with js-test-driver built-in.
In order to run the tests you first need to start the test server. From the sdk
directory run:
./brjs test-server --no-browser
In your browser navigate to http://localhost:4224/capture
. This is the browser window/tab
that the test server will instruct to execute your tests.
Now that the test server is running open another terminal/command prompt and execute
the following from the sdk
directory:
./brjs test ../apps/modularapp/blades/input
This will execute all the tests it finds within that directory. For now, this is just the single test that we've written.
You should see output similar to the following:
› ./brjs test ../apps/modularapp/blades/input
Testing tests (UTs):
Chrome: Reset
Chrome: Reset
E
Total 1 tests (Passed: 0; Fails: 0; Errors: 1) (1.00 ms)
Chrome 36.0.1985.125 Mac OS: Run 1 tests (Passed: 0; Fails: 0; Errors 1) (1.00 ms)
InputViewModelTest.testSomething error (1.00 ms): TypeError: undefined is not a function
TypeError: undefined is not a function
at InputViewModelTest.testSomething (http://localhost:4224/test/tests/InputViewModelTest.js:7:53)
Tests failed: Tests failed. See log for details.
Tests Failed.
Let's fix that error by updating the test to access the correct property of the View Model and to check for an empty string:
var InputViewModelTest = TestCase( 'InputViewModelTest' );
var InputViewModel = require( 'modularapp/input/InputViewModel' );
InputViewModelTest.prototype.testDefaultMessageIsEmpty = function() {
var model = new InputViewModel();
assertEquals( '', model.message() );
};
If you run the brjs test
command the test will now pass:
› ./brjs test ../apps/modularapp/blades/input
Testing tests (UTs):
Chrome: Reset
Chrome: Reset
.
Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (1.00 ms)
Chrome 36.0.1985.125 Mac OS: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (1.00 ms)
Tests Passed.
We've now written our first test and made it pass.
For full details see the Running Test documentation.
Now that you know how to write and run tests you can also write test that assert the functionality the Blade is to provide:
buttonClicked
should return false
buttonClicked
returning true
.Heads Up! test functions must have a name with the test
prefix e.g. testThisThing
Congratulations! The basic functionality for this Blade is complete. It's time to commit your changes locally and push them to github.
git add blades/input
git commit -m 'basic input blade functionality'
git pull origin master
git push origin master
If you've completed this really quickly you can always try creating another Blade.