My team has had the occasional problem of developers pushing Karma/Protractor tests containing the .only() function call, which of course makes our Jenkins etc only run that particular test, potentially allowing bugs to slip by. As such I thought I'd try and figure out a way to stop this from happening without being discovered.
First, I thought I'd look into simply using JSHint to point out the function call, but I can't seem to find a way to do that. I also looked at ESLint for its custom plugins, but I can't figure out how to write a plugin for this particular case.
Could you guys give me some ideas on how to solve this issue? Alternative solutions are also appreciated, of course!
Here's a (probably not working example) of how to create a plugin that flags an error if the parser ever sees a only() call. Again, mileage may vary, but it should be enough to get you started. This does not work if it sees a.only(), we'll leave that up to you.
module.exports.rules = {
"no-only-call": context => ({
CallExpression: (node) => {
if(node.callee.name == "only"){
context.report(node, 'Calls to only() are disallowed');
}
}
})
};
https://www.kenneth-truyers.net/2016/05/27/writing-custom-eslint-rules/ - Simple example of creating a custom rule
http://esprima.org/demo/parse.html - Use this online parser to help you understand the parse tree.
https://www.npmjs.com/package/generator-eslint - Use this generator to start your plugin project
Related
I've been struggling with going back to the roots of doing non-node reliant javascript, in this particular case for a test. Like many developers, i've fallen into the trap of learning frameworks, and in turn have forgotten / never understood some of the basic paradigms with javascript programming.
The problem
I'm trying to test a simple es6 script i've created for a collapsible element. It can be tested with a framework, however the script is simply inserted into the bottom of a html file, rather than be executed in any more complex way, and needs to remain functional without a complex procedure behind it. I understand that this is not the conventional way to do this, you could easily make the problem trivial with modern tech, but it's the way i'm required to put this together.
Collapsible.js
const initialiseCollapsible = (collapsible) => {
let collapsibleButton = collapsible.querySelector(".collapsible__button");
let collapsibleContent = collapsible.querySelector(".collapsible__content");
collapsibleButton.setAttribute("aria-expanded", "false");
collapsibleContent.setAttribute("aria-hidden", "true");
collapsibleButton.addEventListener("click", () => {
// cast the value of aria-expanded as a boolean
let expanded =
collapsibleButton.getAttribute("aria-expanded") === "false"
? false
: true;
// Toggle the expanded attribute
collapsibleButton.setAttribute("aria-expanded", !expanded);
collapsibleContent.setAttribute("aria-hidden", expanded);
});
};
(() => {
[...document.getElementsByClassName("collapsible")].forEach((collapsible) => {
initialiseCollapsible(collapsible);
});
})();
The file is meant to loop through all instances of .collapsible, adding event listeners so they can toggle correctly, and closing them initially (The content has to be accessible with javascript disabled).
1) Module functionality
With es6 moduling, i'm aware that it's transpiled normally using something such as babel. And with requireJS, I still don't understand whether module.exports is going to be understood by the browser, currently it throws errors because it doesn't understand the syntax. Is there a way of going around this? So I can write a functional script to be called in a html file, while still being able to import this into a test file to run tests on? I'm assuming I could just end up copy and pasting it for the sake of having it available is necessary.
2) Testing the thing
I'm struggling to contemplate how to test this piece of code accurately. I see a few potential tests:
Given a collapsible html element,
The expanded / hidden are correctly set to start (testing the query selector works and that the set attributes are working correctly)
Problem I don't quite understand how to emulate this without some sort of virtual dom that I can tamper with, are there good libraries for this? Ones that will allow me to create a document htmlelement that I can run the script code on to see the changes.
The collapsible button now has a clickEvent on it that matches the code of the example. Problem This feels almost like a functional test to me, i'm testing that something happens when I click the button, almost like cucumber / selenium would be a better route for this. There's a large amount of overhead there for something so simple however, is there an easier way to do this?
I realise this is probably around 10 questions in 1, but if you have any feedback / solutions for the problems posed, feel free to contribute.
A little bit of backstory:
We're trying to address a bug on a local library we have.
I was trying to convince the senior developers of changing naming convention when using word like these:
enable disable hide unhide
because they were using
enable disable hide undelete
We discussed the fact of this being a breaking change and will stop other products from working.
So it was disscused to add the unhide without taking the undelete out so that it does not break anything and in the process, if the user uses either unhide or undelete they should still do the same in theory.
Here comes the programming problem now:
This is my function:
toggleAction(data._id, 'undelete', (err, data) => { // cool stuff }, false)
How can I continue to pass a string (without converting to an array or object) but also start passing 2 values so that the changes have to be made in this file and not in the projects side validating, etc.
Another thing, this function will default if the switch case does not found the string.
Also thought about sending two request at the same time but that's just bad programming.
Also though of fallback to another request with the other naming, but since the switch case will still default if it's not in the options, it will not throw an error to actually do the callback for the next function.
What do you guys think is the right approach for something simple and yet capable of breaking a lot of things.
Thanks in advance.
Kinda opinion based, but it's the wrong approach imho.
I would change the word undelete to unhide only on the rendered websites and keep the internal API the same way until the senior devs can fix the breaking changes.
So the user would see the word 'unhide' on their screen, but the API will still stay 'undelete'.
In more complex applications, you'd use an enumeration list so you can change the labels as many times as you want:
const enum_options = [
'enable',
'disable',
'hide',
'show'
];
// 3 is the index of the word 'show'
toggleAction(data._id, 3, (err, data) => { // cool stuff }, false)
That way the API never has to change when you change the labels to any word you desire. Which will also help alot if you ever have to support multiple languages.
ps:
1) if this is a breaking change, there's an issue with the architecture used.
Fix the issues instead of adding even more fragile code. Switching to like using a string 'undelete-unhide' will still need alot of api changes if the entire app has the word 'undelete' written everywhere at the moment.
2) The opposite of hide is usually 'show', not unhide.
I would like to know if organizing JS functions in object notation is a good or bad practice. The intention is to keep js organized/easy to maintain.
Example:
var helper = {
myAlert: function(){
return alert('Alert from helper');
},
toLowerCase: function(){
var str = document.getElementById("txt").innerHTML;
return alert(str.toLowerCase());
}
}
Html:
<body>
<h1 onclick="helper.myAlert()">Hello Plunker!</h1>
<p id="txt" onclick="helper.toLowerCase()">Testing LowerCaseFunction</p>
</body>
Plunker
Thanks in advance!!!
code organization is an strategic topic when it comes to make software survive more than a couple of years yet this is also a very opinionated terrain.
You can make a nice job by keeping semantically related functions near each other under the same namespace, or even make it related to the user story being solved, it can be done in many ways.
If you want to know this approach is good enough, simulate an iteration on it, add a new feature and see what happens to the code.
The code avoids duplication? It gets reusable? Is it easy to locate and relate with the user needs? If so, then it will help you.
Finally, if applicable consider to use some module builder, webpack or browserify for example, so you will be able to not only separate your modules logically but "physically" too.
For me it is a good practice. When working with little projects, you do do see it important, but in large projects you are almost obliged to do it.
simply imagine you are making a chat website, you will need to create function that will delete messages, add messages. you can simply do it as you did it up.
var messages = {
remove:function{//remove code},
add:function{//add code}
}
in this way you can define contacts management object as
var contacts = {
remove:function{//remove code},
add:function{ //add code},
block:function{//block code}
}
This isn't really an answer per se but too long for a comment:
Since you are asking about best practices I'd like to point out a few things in your sample:
onclick. Just...don't. You don't want to grep through your JS trying to diagnose a behavioral problem only to realize 8 hrs in that its being called from HTML. That's a maintenance nightmare waiting to happen.
innerHTML again, just...don't. Unless you are working with HTML. 9 times out of 10, textContent will do and you can assign to it without security risk. Google 'innerHTML security risk' for more info.
alert alert blocks. Blocks your whole browser until you click annoying box. And which of your 50 open tabs was it in? Blocking is bad. Use console.log. You're a dev, and you do have devtools open right?
Your toLowerCase function. You mix data access (getting the DOM element's text) with data transformation. Bad idea.
Note that none of these are particular to JavaScript, they apply to pretty much all UI coding: don't mix business logic with the presentation layer, don't block user interactions, use the principle of least privilege, don't mix data access with data processing, etc. And all of the above issues are bigger problems than whether or not you namespace some functions.
I am new to this very very nice Linq.js library that I have just discovered. I am following the examples to write queries like:
Enumerable.from(jsonArray).select(...); // noice
Can I do this shortcut?
jsonArray.select(...); // error as expected
I read the tests in library, seems like pretty much every call starts with Enumerable.someCommand();. I am wondering if the linq commands have been applied to the correct prototypes in js, so I can call them in the style of 2nd line of code. am I not aware of it because I am a newbie?
I am the creator of the open source project http://www.jinqJs.com.
You could simply do jinqJs().from(jsonArray).select();
Let me know if I could be of any more help
If your concern is that Linq.js doesn't extend the Array prototype, I think it's misplaced. It's not exactly a light framework, kinda the same reason why jquery doesn't do the same thing. You shouldn't expect anything to work on just anything.
If you wanted to make bridging that gap a little nicer, it should be safe to add some methods to convert to the other.
if (!Array.prototype.AsEnumerable) { // not likely to be used by others
Array.prototype.AsEnumerable = () => Enumerable.From(this);
}
Then that would allow you to do:
jsonArray.AsEnumerable().Select(...);
I'm currently developing a tutorial site for teaching the fundamentals of Web development (HTML, CSS, and JavaScript, for starters). I'd like a setup where I could give in-depth coverage of all sorts of topics and then provide a basic sandbox environment where the user could write code which solves the question asked at the end of each tutorial section.
For example, if I'd covered multiplication in a previous tutorial, and the user had just finished a lesson on functions being capable of returning values, I might request that they submit a function which returns the product of two parameters.
Is this not the perfect instance in which using dynamic function creation would be considered a good idea? Let's look at an example.
<script>
function check()
{
eval('var f = ' + document.getElementById('user_code').value);
if (f(5, 10) == 50)
{
// user properly wrote a function which
// returned the product of its parameters
}
}
</script>
Is this at all a bad idea? If so, please explain.
This sounds like it could work. However, the biggest challenge in your environment might be error handling. Students will surely make all sorts of errors:
Compile time errors, that will be detected in eval()
Run time errors, that will be detected when you call the function
Undetectable run time errors, such as an infinite loop or a stack overflow
A more elaborate approach might parse the entered Javascript into a parse tree representation, then compare it to an expected parse tree. If it does not match, then point out what might be wrong and have the student try again. If it does match, then you can eval() and call the function, knowing that it will do what you expect.
Implementing a lexer and parser for Javascript in Javascript would be challenging but certainly not impossible.
Should work as long as you're operating this in a closed environment. Eval opens you up to code injection attacks so I wouldn't put this on a publicly accessible web site, but if it's completely contained within your class room you should be ok.
The code would work, but what if there is an error both syntactically or otherwise ? Perhaps use a try block to catch any error and display it to the user would help things a little...
Not sure if this helps.
Sounds like you want to remake Firebug or even the new Developer Tools in IE8. Due to that, I'm going to have to say there is never a useful case. Not to mention the possibilities of script injection if this site goes public.
In your case, I feel that there is nothing wrong with this. Alternatively you can run the code by using new Function() to build stuff first and then run it. In theory, this would separate the stages of "compiling" and executing. However eval will check the code first and throw errors anyway:
var usercode = document.getElementById('user_code').value;
try {
var f = new Function( 'a','b','return (' + usercode + ')(a,b);' );
if ( f( 5, 10 ) ) {
// user properly wrote a function which
// returned the product of its parameters
}
else {
// user wrote code that ran but produced incorrect results
}
}
catch ( ex ) {
// user wrote something really bad
}
The problem with doing things in this manner is that the exceptions thrown may be nonsensical. "foo;;=bar" will report a "missing ) in parenthetical" error while eval will throw a propper syntax error. You could bypass this by (regexp) grabbing the parameters and body from the user code first and then building it. But then, how would this be any better than an eval?
I think that your real problem will be helping users avoid the pitfalls of implicit globals. How are you going to help users avoid writing code that only works the second time it runs because a global was set the first time? Will you not need to implement a clean sandbox every run? I would take a look at how jsbin.com, firebug and similar tools handle these things.
My feeling is that you should go with eval for now and change it for more elaborate stuff later if the need arrises.