We can now start adding tests for the different things that the OP says that are relevant to the problem wanting to be solved.
[quote=“designtrooper, post:1, topic:292711, full:true”]
Click edit,try to edit one of the values in the input boxes and see a name attribute being added to the input or removed if the user chooses to type in the original value.[/quote]
We have already tested for clicking the Edit button.
Testing that the name attribute changes means triggering the change event on the input field.
function triggerEvent(name, el) {
var event = document.createEvent('Event');
event.initEvent(name);
el.dispatchEvent(event);
}
...
it("adds a name attribute when the value is changed", function () {
var editButton = document.querySelector(".editservices");
var input = openServices.querySelector("input");
editButton.click();
expect(input.name).toBe("");
input.value = "test";
triggerEvent("change", input);
expect(input.name).toBe("form[0][service]");
});
It looks like the editButton
variable will be needed by pretty much all of the tests, so we can declare it at the top, and assign that in the beforeEach() function instead:
var editButton;
beforeEach(function () {
editButton = document.querySelector(".editservices");
});
...
it("shows the edit buttons", function () {
// var editButton = document.querySelector(".editservices");
var buttons = document.querySelector("#buttons");
...
});
it("adds a name attribute when the value is changed", function () {
// var editButton = document.querySelector(".editservices");
var input = openServices.querySelector("input");
...
});
And returning it back to the original value should result in the name attribute being empty.
it("removes the name attribute when the value is returned back to how it started", function () {
var input = openServices.querySelector("input");
editButton.click();
input.value = "test";
triggerEvent("change", input);
input.value = input.defaultValue;
triggerEvent("change", input);
expect(input.name).toBe("");
});
A strange bug occurs because Jasmine does the tests in a random order. When the last test is the first one to occur, the input value is “test” instead of “hair”. Moving the afterEach code into the beforeEach function fixes that strange oddity.
This goes to show that it’s important that each test has the same initial starting conditions.
beforeEach(function () {
openServices.innerHTML = initialHTML;
serviceManager.init();
editButton = document.querySelector(".editservices");
});
afterEach(function () {
// openServices.innerHTML = initialHTML;
// serviceManager.init();
});
Instead of using afterEach, I’ll put it in afterAll so that the page is ready for us to use if we want to do anything manually with it too.
afterAll(function () {
// openServices.innerHTML = initialHTML;
// serviceManager.init();
});
The next test involves the cancel button.
[quote=“designtrooper, post:1, topic:292711, full:true”]
There is one more case when the original values are restored…that is when he clicks the cancel button…the code that does that is at lines 60-64(it only applies for the services input).[/quote]
The test for doing this is:
it("removes the name attribute when cancelled", function () {
var input = openServices.querySelector("input");
var cancelButton = openServices.querySelector("#cancelserv");
editButton.click();
input.value = "test";
triggerEvent("change", input);
triggerEvent("click", cancelButton);
expect(input.name).toBe("");
});
But, the test doesn’t pass because the name attribute is still form[0][service]
from when the field was changed.
[quote=“designtrooper, post:1, topic:292711, full:true”]
My problem is that once the original values are restored(with the aforementioned way) the name attribute is not removed as it should be and as it is the case if the user does manually(by typing the original value).[/quote]
Aha - so the test is correctly showing the problem.
We can now return back to the list of tasks being done:
- Create tests for existing relevant code
- Get and install Jasmine
- Localise images to improve testing speed
- Protect the HTML code from effects of the tests
- Test the edit section
- Test clicking the edit button
- Create test to exercise the existing problem
- Fix the problem, using the test to confirm that it’s fixed
[quote=“designtrooper, post:1, topic:292711, full:true”]
What is wrong here?Is the cause which event comes first?And if yes how to fix it?[/quote]
Well let’s find out. We can add some console.log statements to show in what order things occur.
it("removes the name attribute when cancelled", function () {
var input = openServices.querySelector("input");
var cancelButton = openServices.querySelector("#cancelserv");
editButton.click();
input.value = "test";
console.log("1. trigger change event");
triggerEvent("change", input);
console.log("2. trigger cancel event");
triggerEvent("click", cancelButton);
console.log("3. expect input.name");
expect(input.name).toBe("");
});
and we can add another console.log in the cancelService function:
function cancelService(e) {
console.log("cancel service");
...
}
We can now examine the console to find out where the “cancel service” occurs, and it’s always shown in the correct place, between 2. and 3.
1. trigger change event
change detected
2. trigger cancel event
cancel service
3. expect input.name
In the cancelService function the while loop resets the input values:
while (i < originals.ser_input_lgth) {
$("input[data-name='service" + i + "']").val(services[i]);
i += 1;
}
But, I see nowhere in there at the name attribute is changed. We can add that to the while loop too:
while (i < originals.ser_input_lgth) {
$("input[data-name='service" + i + "']").val(services[i]);
$("input[data-name='service" + i + "']").attr("name", "");
i += 1;
}
And running the test confirms that things are now working.
- Create tests for existing relevant code
- Get and install Jasmine
- Localise images to improve testing speed
- Protect the HTML code from effects of the tests
- Test the edit section
- Test clicking the edit button
- Create test to exercise the existing problem
- Fix the problem, using the test to confirm that it’s fixed
There’s no need for the console.log statements now, and they can be removed, leaving us with the following test code:
it("removes the name attribute when cancelled", function () {
var input = openServices.querySelector("input");
var cancelButton = openServices.querySelector("#cancelserv");
editButton.click();
input.value = "test";
triggerEvent("change", input);
triggerEvent("click", cancelButton);
expect(input.name).toBe("");
});
The test performed an important aspect here. It doesn’t just document how the code is supposed to work, it does more than that.
Before making the code change the test was clearly exposing the problem. After the code change the very same test was confirming that the code is works properly.
With any future changes to the code, the same tests will also help to warn us if any regressions occur too.
The test code that we currently have is:
/*jslint browser*/
/*global serviceManager, beforeEach, afterAll, describe, it, expect*/
describe("service manager", function () {
"use strict";
var openServices = document.querySelector(".openservices");
var initialHTML = openServices.innerHTML;
var editButton;
beforeEach(function () {
openServices.innerHTML = initialHTML;
serviceManager.init();
editButton = document.querySelector(".editservices");
});
afterAll(function () {
openServices.innerHTML = initialHTML;
serviceManager.init();
});
function triggerEvent(name, el) {
var event = document.createEvent('Event');
event.initEvent(name);
el.dispatchEvent(event);
}
function isVisible(el) {
return (el.offsetParent !== null);
}
describe("edit", function () {
it("shows the edit buttons", function () {
var buttons = document.querySelector("#buttons");
expect(isVisible(buttons)).toBe(false);
editButton.click();
expect(isVisible(buttons)).toBe(true);
});
it("adds a name attribute when the value is changed", function () {
var input = openServices.querySelector("input");
editButton.click();
expect(input.name).toBe("");
input.value = "test";
triggerEvent("change", input);
expect(input.name).toBe("form[0][service]");
});
it("removes the name attribute when the value is returned back to how it started", function () {
var input = openServices.querySelector("input");
editButton.click();
input.value = "test";
triggerEvent("change", input);
input.value = input.defaultValue;
triggerEvent("change", input);
expect(input.name).toBe("");
});
it("removes the name attribute when cancelled", function () {
var input = openServices.querySelector("input");
var cancelButton = openServices.querySelector("#cancelserv");
editButton.click();
input.value = "test";
triggerEvent("change", input);
triggerEvent("click", cancelButton);
expect(input.name).toBe("");
});
});
});
The full code can be downloaded from https://www.dropbox.com/s/yn0x14jbcho3efk/service%20manager.zip?dl=0