How would a test method look in QUnit if I am testing validation functions written for a form? Say, if the form needs to check for name field not being null and my function that tests this functionality looks like
function validNameCheck(form)
{
if (document.forms["formSecond"]["nameFull"].value=="")
{
alert("Name Field cannot be empty")
return false;
}
else
return true;
}
What would be a possible QUnit test case for the above?
Lets say that the parameter you are passing to the validNameCheck function is the name element in a form that you want to check if is empty or not, I mean something like this:
var myName = document.forms["formSecond"]["nameFull"];
Then your function should look like this:
function validNameCheck(form){
if (form.value==""){
alert("Name Field cannot be empty")
return false;
}else{
return true;
}
}
Note that I'd change the hardcoded element that you were checking.
Then your QUnit test should look like this:
QUnit.test( "CheckingName", function( assert ) {
var value = false;
assert.equal( value, validNameCheck(myName), "We expect the return to be false" );
});
I would take #Gepser's solution a bit further (although it is certainly part of the solution). If you want to grab the form by it's name, then you probably want to use QUnit's fixture for resetting HTML before each test. Then you might want to mock out the alert method so that you don't get a bunch of them while you're testing.
In the QUnit HTML file:
<body>
<div id="qunit"></div>
<div id="qunit-fixture">
<!-- Anything in here gets reset before each test -->
<form name="formSecond">
<input type="text" name="nameFull">
</form>
</div>
...
</body>
Then in your QUnit tests (either in that HTML file our in their own JS file):
QUnit.begin(function() {
// mock out the alert method to test that it was called without actually getting an alert
window.alert = function() {
window.alert.called++;
};
window.alert.called = 0;
});
QUnit.testDone(function() {
// reset the alert called count after each test
window.alert.called = 0;
});
...
// From #Gepser's answer...
QUnit.test( "CheckingName", function( assert ) {
var value = false;
assert.equal( value, validNameCheck(), "We expect the return to be false" );
// add an assertion to make sure alert was called
assert.equal( 1, window.alert.called, "alert was called only once" );
});
Related
Alright, so I'm having a bit of a problem. I have an app that displays some facts via a search input. If that fact isn't existing, I want to display an error.
I'm producing that error via Node on the backend, and via EJS sends the error message to the HTML (.ejs) and javascript files.
Long story short, the error message displays correctly, but the error popup also displays when refreshing the page, even though there isn't any errors to display.
Error.js
var clientError = "<%=clientError%>"; //<--- (1) see comment below
$("#error").hide();
if(clientError !== "") { //<--- (2) see comment below
$("#error").fadeIn().show();
setTimeout(function(){
$("#error").fadeOut().hide();
}, 4000);
}
(1) This is being interpreted as the word "clientError" and characters "<%=%>" of "<%=clientError%>", and NOT the value of the .ejs query, for example, "An error occurred". This leads to problem no. 2, see below.
(2) Because "<%=clientError%>" isn't being read as an empty string, even if there aren't any errormessages, it runs the code either way and displays the error-popup. So when I refresh the website I get the popup, because the string isn't empty (even though it doesn't display any message, because there aren't any errors).
I have also tried some other variants of the error.js code, for example:
if(clientError.length >= 17) ...executes error popup // no luck with this either, see comment 1 and 2 above.
//I have also tried not defining clientError in App.js:
var clientError;
//And then inside error.js:
if(clientError !== undefined) ...executes error popup //no luck with this, since error.js reads it as a defined string.
App.js
var clientError = ""; //<-- (3)
...
...
app.get("/:option/:input", function(req, res) {
var opt = req.params.option;
var inp = req.params.input;
Article.find({
option: lodash.capitalize(opt),
input: lodash.capitalize(inp)
}, function(err, foundArticle) {
if (err) {
clientError = "Internal Server Error. Contact Administrator.";
setTimeout(function(){
clientError = "";
},4000);
console.log(err);
}
else if ((!foundArticle) || (foundArticle.length <= 0)) {
const notFound = new Notfound({
option: searchOptions,
input: searchInput
});
clientError = "Article not found. Try again."
setTimeout(function(){
clientError = "";
},4000);
res.redirect("/");
} else {
Article.findById(someIdOrSomething, function(err, someArticle){
res.render("page", {
...
clientError: clientError,
});
});
}
});
})
(3) An empty string. So the string in error.js should be read as an empty string, shouldn't it?
At last, we have the error.EJS
error.ejs
<div id="error" class="error-popup">
<h4>An error occurred.</h4>
<p id="errormessage"><%=clientError%></p>
</div>
One idea might be to have an input instead of the paragraph element above that's disabled as such...
<input id="errormessage" disabled type="text" value="<%=clientError%>">
... and then use Jquery to get the value of the input.
EDIT:
The idea above worked! Here is the new code:
error.js
$("#error").addClass("error-popup");
if($("#errormessage").val() !== "") {
$("#error").fadeIn().addClass("show-error-popup");
setTimeout(function(){
$("#error").fadeOut().removeClass("show-error-popup");
}, 4000);
}
error.ejs
<div id="error" class="error-popup">
<h4>An error occurred</h4>
<input id="errormessage" disabled type="text" value="<%=clientError%>">
</div>
Next step is just to style the input so it doesn't look like a regular input.
I have a jQuery function that will be run when user click a submit button of form is submitted
FUNCTION #1
jQuery(function($){
$('#filter').submit(function() {
var filter = $('#filter');
$.ajax({
url:filter.attr('action'),
data:filter.serialize(), // form data
type:filter.attr('method'), // POST
beforeSend:function(xhr){
filter.find('button').text('Filtering...'); // changing the button label
},
success:function(data){
filter.find('button').text('Filter'); // changing the button label back
$('#response').html(data); // insert data
}
});
return false;
});
});
<form action="<?php echo site_url() ?>/wp-admin/admin-ajax.php" method="POST" id="filter">
I have other script with javascript that run when user click on link with id "link-id".
FUNCTION #2
$div1 = $(".div1");
$div2 = $(".div2");
$div1.hide()
$div2.hide()
function showDiv(){
if(document.getElementById('chk1').checked){
$div1.show()
} else {
$div1.hide()
}
if(document.getElementById('chk2').checked){
$div2.show()
} else {
$div2.hide()
}
}
$('#link-id').on('click', showDiv)
<a id="link-id" class="btn btn-primary" href="javascript: void(0)">Go ahead</a>
I'd like to add and if and else in the FUNCTION #2 that:
if jQuery 'FUNCTION #1' is not submitted (run), javascript 'FUNCTION #2' do something (current code);
if user has already click one time on button to run 'FUNCTION #1', the 'FUNCTION #2' shall do other thing.
I'm not expert with javascript code.
Is there a way to made this check?
If I'm understanding you correctly the two functions are called from different event which means at different times.
If the scripts are linked (by integrating both in the html) or in one:
Then you could add a global variable that changes in function 1 and is being checked in function 2.
Declaration:
let functionOneWasExectuted = false;
In function 1:
functionOneWasExectuted = true;
In function 2:
if (functionOneWasExectuted) {
// code function 1 has been executed before
} else {
// code function 1 has not been executed before
}
If the 2 scripts are not linked in any way let me know and I'll post a different solution :)
Ok, so I have a text field in which I type a string and I have a button next to it.
<div class="sidebar-search">
<div class="input-group custom-search-form">
<<label for="riot-summoner-input">Search a Summoner</label><br>
<input type="text" id="riot-summoner-input" class="form-control" placeholder="Type summoner name..." style="margin-bottom: 20px">
<button type="button" id="valid-summoner">Search</button>
</div>
</div>
By Clicking on this button, the following script gets executed
let res = {{ summoner.summonerLevel }}
$(document).ready(function() {
// Get value on button click and pass it back to controller
$("#valid-summoner").click(function () {
const summoner_input = $("#riot-summoner-input").val();
console.log(summoner_input)
let url = `/coach/?summonerName=${summoner_input}`
history.replaceState(summoner_input, 'Coach Index', url);
console.log(url)
function loadXMLDoc()
{
document.getElementById("display-summonerLevel").innerHTML = `Summoner Level: <h2>${res}</h2>`
}
loadXMLDoc();
});
});
Now as far as I can understand this will change my page url to include the value inserted in the text field and will send it back to my controller without refreshing the page, which it does.
Now in my Controller I'm using that value to do some logic with it
/**
* #Route("/", name="app_coach_index", methods={"GET"})
*/
public function index(CoachRepository $coachRepository, riotApi $callRiot, Request $request): ?Response
{
$value = $request->request->get('summoner_input');
if($value != null){
$this->debug_to_console($value . "Hi");
return $this->render('coach/index.html.twig', [
'coaches' => $coachRepository->findAll(), 'summoner'=> $this->showSummoner("$value")
]);}
else{
$this->debug_to_console($value);
return $this->render('coach/index.html.twig', [
'coaches' => $coachRepository->findAll()
]);
}
}
Now it's interesting to note that I'm doing this in the index function.
Here's the function I'm calling within the index function which is actually the one that gets the value from the script
/**
* #Route("/?summonerName={summoner_input}", name="show_summoner", methods={"GET"})
*/
public function showSummoner($summoner_input)
{
$call = new ApiClient(ApiClient::REGION_EUW, 'API-KEY-HERE');
return $call->getSummonerApi()->getSummonerBySummonerName($summoner_input)->getResult();
}
Now that I'm seeing this I can see that the issue is I'm getting the value in the showSummoner() function but trying to use it in the index function. Which is why I'm not getting a value when I print it to console and the variable is undefined.
Honestly I can't think of any logic I can do to overcome this issue.
EDIT!!!!!!!
Okay, so I know where the problem is arising, the issue is when I'm calling showSummoner($value) within index function. I'm using $value = $request->query->get('summoner_input');
I thought I was getting that value in the index function when in fact I'm getting it in the showSummoner() function. You can tell by the annotations
For index I don't have a parameter in its url, whereas in showSummoner() I have a parameter in the annotations as such.
/**
* #Route("/?summonerName={summoner_input}", name="show_summoner", methods={"GET"})
*/
This is indeed the fact because I'm using that url in the script as such
let url = `/coach/?summonerName=${summoner_input}`
The reason for this is I can't use the parameter in the index url because then I would have to provide the parameter in all the other places I'm using index in even when I don't have a parameter meaning I didn't search for anything.
I hope this gives more clarification
You're trying to get a value from $_GET global, not $_POST.
You can replace :
$value = $request->request->get('summoner_input');
by:
$value = $request->query->get('summoner_input');
You are trying to access the GET parameter using the wrong name ('summoner_input').
$value = $request->request->get('summoner_input');
When you are setting it as summonerName here:
let url = `/coach/?summonerName=${summoner_input}`
You will also want to pass a default value to check for, as the second parameter.
Try this:
$value = $request->request->get('summonerName', false);
if(false !== $value){
/* the parameter is in the url */
}
I need to add the value of a callback into my setAttribute. How do I do that?
This value is necessary to get data out of a table at a later moment.
This is the code:
row.forEach(function(row) {
var subchapname = document.createElement("div");
subchapname.setAttribute("id", "subchaptertitle");
subchapname.setAttribute("subid", '"+row+"');
subchapname.setAttribute("onclick","{ alert('You are not going to believe this!') } ");
subchapname.textContent = row.subname;
rows.appendChild(subchapname);
Basically, this means:
callback = row
This callback needs to be added to subchapname.setAttribute("subid", '"+row+"');
Is this possible?
This is the actual result:
<div id="subchaptertitle" subid=""+row+"" onclick="{ alert('You are not going to believe this!') } ">bos in brand</div>```
subid is not attribute to store data in it, so you can not add a attribute like this to a html-tag and fill it with a value (Of course writing a string into it, would work, but is this what you need?). But you can add datasets if you use html5. So use this solution to store your rows-value in the dataset-property of subid.
If row is a object and you want to see the the stringified value of the Object use JSON.stringify before storing it in the dataset
row.forEach(function(row) {
var subchapname = document.createElement("div");
subchapname.setAttribute("id", "subchaptertitle");
subchapname.dataset.subid = row;
// subchapname.dataset.subid = JSON.stringify(row);
subchapname.setAttribute("onclick","{ alert('You are not going to believe this!') } ");
subchapname.textContent = row.subname;
rows.appendChild(subchapname);
});
Your Element should now look like this:
<div id="subchaptertitle" onclick="{ alert('You are not going to believe this!') } " data-subid="[object Object]"></div>
Or if you used JSON.stringify:
<div id="subchaptertitle" onclick="{ alert('You are not going to believe this!') } " data-subid="what ever row is as a string"></div>
To log the value to the console, (after you added the tag to the DOM) do something like this:
console.log(document.getElementById('subchaptertitle').dataset.subid);
In case you used JSON.stringify, now use something like this:
console.log(JSON.parse(document.getElementById('subchaptertitle').dataset.subid));
In this scenario I'm using the ui-bootstrap typeahead to capture an object from an external api. Using the select callback I'm getting that object and have the results set in a separate function within my controller.
The issue is that I want to take those results and send them off to a separate api with a click function I already have set up. My question is how do i get the results of the type-ahead into the click function to post? The user flow is as follows.
<div>
<input type="text" placeholder="Find A Game"
typeahead-on-select="setGames($item)"
ng-model="asyncSelected"
typeahead="test.name for test in getGames($viewValue)"
typeahead-loading="loadingLocations" typeahead-min-length="3"
typeahead-wait-ms="500" typeahead-select-on-blur="true"
typeahead-no-results="noResults">
</div>
<div ng-show="noResults">
No Results Found
</div>
<button ng-disabled="!asyncSelected.length"
ng-click="addtodb(asyncSelected)">Add To Database</button>
As you can see the label is set to the items name and this works fine. When the user selects the name I then use typeahead-on-select="setGames($item)" to send off the entire object to its own funtion. From there I want to take the object and pass it to another function that you can see within the button tags ng-click. I currently have it passing the model, but what I really want is to pass the entire object within $item from the select event. So far my controller looks like this:
angular.module('2o2pNgApp')
.controller('GiantCtrl', function ($scope, $http, TermFactory, $window, SaveFactory) {
$scope.getGames = function(val) {
return $http.jsonp('http://www.example.com/api/search/?resources=game&api_key=s&format=jsonp&limit=5&json_callback=JSON_CALLBACK', {
params: {
query: val
}
}).then(function(response){
return response.data.results.map(function(item){
return item;
});
});
};
$scope.setGames = function (site) {
var newsite = site;
};
$scope.addtodb = function (asyncSelected, newsite) {
TermFactory.get({name: asyncSelected}, function(data){
var results = data.list;
if (results === undefined || results.length === 0) {
SaveFactory.save({vocabulary:'5', name:newsite.name, field_game_id:newsite.id}, function(data) {
$window.alert('All Set, we saved '+asyncSelected+' into our database for you!')
});
} else {
// do stuff
});
}
});
No matter what I do I cant seem to pass the entire $item object into this click function to post all the info i need.
Via New Dev in Comments:
$item is only available locally for typeahead-on-select... you can
either assign it to some model within your controller, or, in fact,
make the model of typeahead to be the item: typeahead="test as
test.name for test in getGames($viewValue)" – New Dev