I'd suggest splitting this up in these parts:
- Test the conversion from input to output, i.e.:
"51" -> "51.0%"
- Test if your method of modifying the
input
value works
- Test whether your attached event listener gets called when it's needed
If all of these tests succeed, you can assume chaining them together will work as well.
To test the conversion method, I'd suggest moving its logic into a separate, pure function. I've pasted your format logic below and removed the setValue
side effect. I included some tests (you should check them out and see if you need more/they match your requirements). I've left two failing tests as an example.
String formating test:
function addPercentSign(val) {
var inputNumber = parseFloat(val);
if (inputNumber) {
if (inputNumber < 50 || inputNumber > 100) {
//see learningCurveFormatCheck
return null;
} else {
var finalVal = inputNumber.toFixed(1);
var finalOutput = finalVal + "%";
return finalOutput;
};
};
};
module("String formatting");
test("Returns undefined for unparseable strings", function() {
["foo", null, NaN, "0.0.0"]
.forEach(function(result, i, arr) {
var result = addPercentSign(result);
strictEqual(result, undefined, arr[i] + " produces " + result);
});
});
test("Returns null for values below 50 and above 100", function() {
["0", "0.0", "25", "49.99999", "100.00000001", "10300", Infinity]
.forEach(function(result, i, arr) {
var result = addPercentSign(result);
strictEqual(result, null, arr[i] + " produces " + result);
});
});
test("Appends a % sign for values between 50 and 100", function() {
strictEqual(addPercentSign("51.0"), "51.0%");
// ...
});
test("Appends a digit for values without one", function() {
strictEqual(addPercentSign("51"), "51.0%");
// ...
});
test("Removes and rounds digits for values with more than one", function() {
strictEqual(addPercentSign("51.999"), "52.0%");
strictEqual(addPercentSign("51.06"), "51.1%");
// ...
});
<link href="https://code.jquery.com/qunit/qunit-1.12.0.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/qunit/qunit-1.12.0.js"></script>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
Now that you've got this method covered, you'll need to find out if you can retrieve values from and write values to an input field. Those are similar to the one you already wrote:
Getting and setting the input's value
function createInput() {
return $('<input id="learningCurveInput" type="text" value="hello world"/>')
.appendTo('#qunit-fixture');
}
module("Writing and reading to input", {})
test("writes to value", function(assert) {
var $input = createInput();
var result = "55";
// Whatever you're using to set:
// in your code, I read `control.learningCurve.setValue`
// if that's what you're using, that's the method you should test
$input.val(result);
strictEqual($input.val(), result);
});
test("reads from value", function(assert) {
var $input = createInput();
// Whatever you're using to get the value
$input.val();
strictEqual($input.val(), "hello world");
});
<link href="https://code.jquery.com/qunit/qunit-1.12.0.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/qunit/qunit-1.12.0.js"></script>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
Now that you know you can (a) correctly transform values, and (b) correctly read and write values, you'll need to test if your get value -> transform value -> set value sequence will be triggered by the correct input. For example:
Testing the event listeners
jQuery has some handy methods for attaching and triggering event listeners. You can use .change
or submit
without an argument to mimic UI input. Alternatively, you can trigger click
on a submit button.
function createForm() {
return $("<form></form>")
.append(createInput());
}
function createInput() {
return $('<input id="learningCurveInput" type="text" value="hello world"/>')
.appendTo('#qunit-fixture');
}
module("Form event listeners", {})
test("input executes method on change", function(assert) {
var called = false;
var onChange = function() { called = true; };
var $input = createInput();
$input.change(onChange);
$input.val("test");
strictEqual(called, false);
$input.change();
strictEqual(called, true);
});
test("form executes method on submit", function(assert) {
var called = false;
var onSubmit = function() { called = true; };
var $form = createForm();
var $input = $form.find("input");
$form.submit(onSubmit);
strictEqual(called, false);
$form.submit();
strictEqual(called, true);
});
<link href="https://code.jquery.com/qunit/qunit-1.12.0.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/qunit/qunit-1.12.0.js"></script>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
Concluding
Now, you can determine if an implementation of your code is covered by your tests:
$("form").submit(function() { // Tested in test 3
var $input = $(this).find("input");
var originalValue = $input.val(); // Tested in test 2
var newValue = addPercentSign(originalValue); // Tested in test 1
$input.val(newValue); // Tested in test 2
});
Notice that it's mainly the first test module that has custom logic and requirements. If you're using jQuery, which is already heavily tested, you won't need to re-implement tests for methods such as .val()
: check their public repo to see the coverage for those. If you're implementing custom methods to interact with the DOM, you do need to test them.
So, in short: rewrite addPercentageSign
to be a pure function that takes a string and returns a string; make sure it's thoroughly tested. Interact with the DOM via a tested library, or write tests for both DOM editing and event listening.