Using jquery selectors in an expect in jasmine - javascript

I've noticed that you when writing jasmine unit tests usually the format is:
expect($('#foo')).toHaveValue('#bar');
But recently I've discovered by accident that the following also works:
expect('#foo').toHaveValue('#bar');
Is this expected behaviour? This seems like a better way to write my expects but I have never seen this notation before and I want to be sure I am not abusing something.
Could anyone confirm this is the way to go or direct me to any documentation of this?
(I am using the jasmine jquery library)

I've played around a bit with that. Looks like it really does work, having some peculiarities, though.
I've tried things like:
expect('.search-form').toBeInDOM();
expect('.search-form').toEqual('div');
expect('.search-form').toContainElement('.search-form__footer');
the first one passes and truely fails when changing to
.not.toBeInDOM();
the third one looks same -- it truely fails is changing to some
bad selector for toContainElement
the second one is a problem because of ambiguity: '.search-form' can be treated both as string and a selector.
Had a very brief look into source code, it looks likes matchers really do resolve expectation actual as a selector (example from):
toBeInDOM: function () {
return {
compare: function (actual) {
return { pass: $.contains(document.documentElement, $(actual)[0]) }
}
}
},
Although I could not find any sign of such abilities in their docs, too. Still, source code is source code ))) and it says what it says. And now it says it will treat the actual for expect as a selector.

Related

How to know how many elements are on a page using codeceptjs

In Codeceptjs, I don't find a way to count the number a certain element is present on the page. The I.assertNumber in the example is some kind of made up clause to hopefully express better what I am looking for.
Scenario('test something', (I) => {
I.amOnPage('http://example.com`);
I.assertNumber((locate('div.someclass'),20);
.. }
You can use seeNumberOfElements or seeNumberOfVisibleElements methods
see in docs (maybe you use other helper(Puppeteer, Protractor, etc), so see in its doc)
https://codecept.io/helpers/WebDriver/#seenumberofelements
https://codecept.io/helpers/WebDriver/#seenumberofvisibleelements

How to cut off function from global scope

I have an idea for a game where people can type in some simple instructions for their character like player.goLeft() or player.attackInFront() and for that I have people type their code into a text box and then I parse it into eval(). This works well but it also allows people to change their own character object by typing things like player.health = Infinity; or something similar. I have a list of functions I want to allow people to use, but I am unsure how to restrict it to only use them.
I understand that the whole point of not letting people use eval is to avoid accidental cross-site scripting but I am unsure on how else to do this. If you have a suggestion please leave a comment about that.
I asked some people around on what to do and most suggested somehow changing scope(which is something I was not able to figure out) or to add some odd parameter to each function in my code that would be required to be a specific string to execute any function, but that seems hacky and since I am making the game in browser with p5js it would be easy to just inspect element and see what the password is.
basically every character has variable called "instruction" which is just a string of javascript. Then every frame of the game I execute it by doing eval(playerList[i].instruction);
tl;dr, how can I only allow specific function to be executed and not allow any others?
EDIT: I forgot to mention that I also am planning to provide player with information so that people can made code that would adapt to the situation. For example there will be parameter called vision that has vision.front and vision.left etc. These variables would just say if there is an enemy, wall, flower, etc around them in a grid. Some people suggested that I just replace some functions with key words but then it compromises the idea of using if statements and making it act differently.
EDIT 2: Sorry for lack of code in this post, but because of the way I am making it, half of the logic is written on server side and half of it works on client side. It will be a little large and to be completely honest I am not sure how readable my code is, still so far I am getting great help and I am very thankful for it. Thank you to everybody who is answering
Do NOT use eval() to execute arbitrary user input as code! There's no way to allow your code to run a function but prevent eval() from doing the same.
Instead, what you should do is make a map of commands the player can use, mapping them to functions. That way, you run the function based on the map lookup, but if it's not in the map, it can't be run. You can even allow arguments by splitting the string at spaces and spreading the array over the function parameters. Something like this:
const instructions = {
goLeft: player.goLeft.bind(player),
goRight: player.goRight.bind(player),
attackInFront: player.attackInFront.bind(player)
};
function processInstruction(instruction_string) {
const pieces = instruction_string.split(' ');
const command = pieces[0];
const args = pieces.slice(1);
if (instructions[command]) {
instructions[command](...args);
} else {
// Notify the user their command is not recognized.
}
};
With that, the player can enter things like goLeft 5 6 and it will call player.goLeft(5,6), but if they try to enter otherFunction 20 40 it will just say it's unrecognized, since otherFunction isn't in the map.
This issue sounds similar to the SQL Injection problem. I suggest you use a similar solution. Create an abstraction layer between the users input and your execution, similar to using parameters with stored procedures.
Let the users type keywords such as 'ATTACK FRONT', then pass that input to a function which parses the string, looks for keywords, then passes back 'player.attackInFront()' to be evaluated.
With this approach you simplify the syntax for the users, and limit the possible actions to those you allow.
I hope this isn't too vague. Good luck!
From your edit, it sounds like you're looking for an object-oriented approach to players. I'm not sure of your existing implementation needs, but it would look like this.
function Player() {
this.vision = {
left: '',
// and so on
}
}
Player.prototype.updateVisibilities = function() {
// to modify the values of this.visibility for each player
}
Player.prototype.moveLeft = function() {
}
Don't give the user an arbitrary interface (such as an input textfield that uses eval) to modify their attributes. Make a UI layer to control this logic. Things like buttons, inputs which explicitly run functions/methods that operate on the player. It shouldn't be up to the player as to what attributes they should have.

jQuery: Unrecognized Expression (getting around this error)

jQuery("input[name=a.b.c]")
Executing this line using jQuery 1.10.2 or 1.9.1 results in the message:
"Syntax error, unrecognized expression: input:hidden[name=a.b.c]".
I understand the core problem which is that the dots are not escaped or quoted out. This would work:
jQuery("input[name='a.b.c']")
The constraint is that I do not have the ability to change the line of code with the bad selector. That line is produced by the website (which I don't own) and they don't give me the ability to change that.
However, they do allow me to add arbitrary JS files to the header of the page (which means I can use a different jQuery version or even edit the jQuery file). My question is whether anyone knows another way around this so that jQuery can cope without the quotes since I cannot change the bad code.
For those saying that I can just change the name, this doesn't help because the JS still throws an error because changing the name of the element doesn't fix the bad selector.
Thanks
The proper way of executing this selector is:
jQuery('input[name="a.b.c"]')
Obviously you need to edit the algorithm that creates this line, there's no way jquery will accept an invalid selector.
Take a look here.
How do I extend jQuery's selector engine to warn me when a selector is not found?
In your case I would do something like this.
var oldInit = $.fn.init;
$.fn.init = function(selector, context, rootjQuery) {
selector = fixItWithQuotes(selector, context, rootjQuery);
return new oldInit(selector, context, rootjQuery);
};
untested by me, but it should give you an idea.
Also, this might give you more ideas?
http://blog.tallan.com/2012/01/17/customizing-the-default-jquery-selector-behavior/
Hope that makes sense.
Why don't you change the name attribute yourself?
var el = $("input");
el.attr("name", el.attr("name").replace(/[\d\.]+/g, ""));
console.log(el.attr("name"));
Then change it back if you need to. jsFiddle here

Chrome extension read innerHTML of the current page?

Hi this may be a silly question, but I can't find the answer anywhere.
I'm writing a chrome extension, all I need is to read in the html of the current page so I can extract some data from it.
here's what I have so far:
<script>
window.addEventListener("load", windowLoaded, false);
function windowLoaded() {
alert(document.innerHTML)
});
}
</script>
Can anybody tell me what I'm doing wrong?
thanks,
function windowLoaded() {
alert('<html>' + document.documentElement.innerHTML + '</html>');
}
addEventListener("load", windowLoaded, false);
Notice how windowLoaded is created before it is used, not after, which won't work.
Also notice how I am getting the innerHTML of document.documentElement, which is the html tag, then adding the html source tags around it.
I'm writing a chrome extension, all I need is to read in the html of
the current page so I can extract some data from it.
I think an important answer here is not the correct code to use to alert the innerHTML but how to get the data you need from what's already been rendered.
As pimvdb pointed out, your code isn't working because of a typo and needing document.documentElement.innerHTML, something you can diagnose in the Chrome console (Ctrl+Shift+I). But that's secondary to why you'd want the inner HTML in the first place. Whether you're looking for a certain node, specific text, how many <div> elements exist, the value of an ID, etc., I'd heavily recommend the use of a library like jQuery (vanilla JS works, but it can be verbose and unwieldy). Instead of reading in all the HTML and parsing it with string functions or regex, you probably want to take advantage of all the DOM parsing functionality already available to you.
In other words, something like this:
$("#some_id").val(); // jQuery
document.getElementById("some_id").value; // vanilla JS
is probably way safer, easier and more readable than something eminently breakable like this (probably a bit off here, but just to make a point):
innerHTML.match(/<[^>]+id="some_id"[^>]+value="(.*?)"[^>]*?>/i)[1];
Use document.documentElement.outerHTML. (Note that this is not supported in Firefox; irrelevant in your case.) However, this is still not perfect as it doesn't return nodes outside the root element (!doctype and possibly some comments or processing instructions). The document.innerHTML property is, AFAIK, specified in HTML5 specification, but currently not supported in any browser.
Just FYI, navigating to view-source:www.example.com also displays the entire markup (Chrome & Firefox). But I don't know whether you can work with it somehow.
window.addEventListener("load", windowLoaded, false);
function windowLoaded() {
alert(document.documentElement.innerHTML);
}
You had a } with no purpose, and the }); should just be }. These are syntax errors.
Also, it's document.documentElement.innerHTML, since it's not a property of document.

Learning jQuery: if & else statements, is this valid?

At the moment I'm learning jQuery and I hit the topic about if/else statements. As I have no background in programming this topic is something that I need to practice a bit more to get a thorough understanding of it.
The book I'm studying gave me the advice of just writing different blocks of if/else statements. I just had an idea and wanted to know if its valid:
$(morningWakeup).ready(function() {
$('#arms').reaction(function() {
if($'#kid').is(':nagging')) {
$('#kid').slap();
} else {
$('#kid').hug();
}
});
});
Let me make it clear that this is a joke of course, but I want to know if this is valid code and if you can supply me with some more examples? Thank you!
The basic form is perfectly fine, though you've misplaced some parentheses on this line: if($'#kid').is(':nagging')) {. It should be if ($('#kid').is(':nagging')) { instead. Also, note that you'll have better luck setting $('#kid').attr('behaving') to true if you just ignore() him/her for a while instead of slap()ing them. Negative reinforcement sucks. :)
You're mixing up Javascript and jQuery here: The if/else is basically valid, but the jQuery part (.is etc.) will strongly depend on whether the DOM elements exist, whether they have that property etc.
I would recommend starting with real live HTML to go along.
That, and of course the syntax error #bcat points out...

Categories