Need to store to css element in variable - javascript

I am trying to make my code more readable in portractor.
I want to store the css class in a variable and need to access that variable on click method.
element.all(by.css("div[ng-click=\"setLocation('report_road')\"]")).click();
element.all(by.css("div[ ng-click=\"mapFeedBack.editObject= mapFeedBack.createMapObjectModel();setLocation(mapFeedBack.noMap?'road_new':'choose_location_road_new/road_new')\"]")).click();
it("test browser should reach report road option",function() //spec2s
{
element.all(by.css("div[ng-click=\"setLocation('report_road')\"]")).click();
expect(browser.getCurrentUrl()).toContain("report_road");
browser.sleep(browser.params.sleeptime);
browser.sleep(browser.params.sleeptime);
});
it("test browser should reach report road missing",function() //spec3
{
element.all(by.css("div[ ng-click=\"mapFeedBack.editObject= mapFeedBack.createMapObjectModel();setLocation(mapFeedBack.noMap?'road_new':'choose_location_road_new/road_new')\"]")).click();
expect(browser.getCurrentUrl()).toContain("choose_location_road_new/road_new");
browser.sleep(browser.params.sleeptime);
browser.sleep(browser.params.sleeptime);
});
So I created two variables in my file :
var road_button ="\"div[ng-click=\"setLocation('report_road')\"]\"";
var road_missing= "\"div[ ng-click=\"mapFeedBack.editObject= mapFeedBack.createMapObjectModel();setLocation(mapFeedBack.noMap?'road_new':'choose_location_road_new/road_new')\"]\"";
And tried to access my css class using that variable:
element.all(by.css(road_button)).click();
element.all(by.css(road_missing)).click();
But some how I'm not able to access these variable value. Can you please provide me the right way of doing this?
Thank you

I think you are sort of reinventing the wheel. What you really need to follow is the guideline to use Page Objects. They would not only solve your problem of separating locators from the test flow and test scenario logic, but would also make the the code more modular and easy to adapt to never-ending changes on the application side.
Here is a great practical introduction to Page Objects in Protractor:
Page Objects

Related

Manipulate values ​between html pages

I'm creating a portfolio, and in that portfolio there will be several cards, and the purpose of these cards will be for them to be redirected to another page with detailed information. And that's where the question comes in, instead of creating an html page for each card wouldn't it be advantageous to make a page only, and change the values ​​between each card when clicked on js ?
A buddy told me that there is a rounter property of react, where it is possible to do this, but the project is simple for now, and I would like to solve this issue with js.
Below is a separate example (which is not part of the main project):
Main page:
Aqui
Teste
Page 2
<div id="main">
<h1 id="title">Lindo</h1>
</div>
Js
let a1 = document.getElementById('a1');
var aa = document.getElementById('aa');
var h1 = document.querySelector('#title');
var main = document.getElementById('main');
if (onclick == a1) {
title.innerText = "Leandro O cachorro";
main.style.backgroundColor = 'green';
}else if(onclick == aa){
console.log('era pra estar vermelho');
title.innerText = "Belle Belinha";
main.style.backgroundColor = 'red';
}
I tried to use the if-else sentence, but it only takes the first if, even clicking on link 2
instead of creating an html page for each card wouldn't it be advantageous to make a page only, and change the values ​​between each card when clicked on js ?
Of course, everyone loves that way.
Frankly speaking, it is possible but you can't achieve this with just what you are showing above. I think you can't achieve what you want in that way.
So instead, I will recommend you to use react. In case you don't like it, take a look of alternatives below.
If you consider react is overkill, you can try a simpler solution: static site generator. Check: Hugo, Jekyll, Eleventy, etc... These approaches help you focus on site building instead of architecture and technical building.
If you want a lighter solution and prefer to do more stuff, then pick a bundler like webpack, rollup, parcel, etc... and then apply templating libraries likes Handlebar JS, Mustache JS, Liquid JS, EJS, etc... This approach will give you more chance to do low-level stuff and super lightweight.
Lastly, build everything from scratch. yes, still possible but sure unless you know most of the things and know where to go, and what to do.
The only one trick I could think of for exchanging information between different pages while only using front-end javascript: You can link to the other page using parameters at the end:
I.E.:
myUrl + "?myParameter1=myValue1&myParameter2=myValue2"
Now on that second page you could retrieve those parameters using:
var url = new URL(window.location.href);
url.searchParams.get("myParameter1"); // "myValue1"
url.searchParams.get("myParameter2"); // "myValue2"
//...
...and depending on the parameter(s) passed, you can now display different content on the page, which can even be bookmarked or even shared via the link (as a nice sideffect).
Edit: Sorry, I might have misunderstood your question, but maybe this helps you to find an alternate solution anyway (at least you won't have to make a new html page for EVERY card, just one).

How to re-evaluate a script that doesn't expose any global in a declarative-style component

I have been writing a reusable script, let's call it a plugin although it's not jQuery, that can be initialised in a declarative way from the HTML. I have extremely simplified it to explain my question so let's say that if a user inserts a tag like:
<span data-color="green"></span>
the script will fire because the attribute data-color is found, changing the color accordingly.
This approach proved very handy because it avoids anyone using the plugin having to initialise it imperatively in their own scripts with something like:
var elem = document.getElementsByTagName('span')[0];
myPlugin.init(elem);
Moreover by going the declarative way I could get away without defining any global (in this case myPlugin), which seemed to be a nice side effect.
I simplified this situation in an example fiddle here, and as you can see a user can avoid writing any js, leaving the configuration to the HTML.
Current situation
The plugin is wrapped in a closure like so:
;(function(){
var changeColor = {
init : function(elem){
var bg = elem.getAttribute('data-color');
elem.style.background = bg;
}
};
// the plugin itslef looks for appropriate HTML elements
var elem = document.querySelectorAll('[data-color]')[0];
// it inits itself as soon as it is evaluated at page load
changeColor.init(elem);
})();
The page loads and the span gets the correct colour, so everything is fine.
The problem
What has come up lately, though, is the need to let the user re-evaluate/re-init the plugin when he needs to.
Let's say that in the first example the HTML is changed dynamically after the page is loaded, becoming:
<span data-color="purple"></span>
With the first fiddle there's no way to re-init the plugin, so I am now testing some solutions.
Possible solutions
Exposing a global
The most obvious is exposing a global. If we go this route the fiddle becomes
http://jsfiddle.net/gleezer/089om9z5/4/
where the only real difference is removing the selection of the element, leaving it to the user:
// we remove this line
// var elem = document.querySelectorAll('[data-color]')[0];
and adding something like (again, i am simplifying for the sake of the question):
window.changeColor = changeColor;
to the above code in order to expose the init method to be called from anywhere.
Although this works I am not satisfied with it. I am really looking for an alternative solution, as I don't want to lose the ease of use of the original approach and I don't want to force anyone using the script adding a new global to their projects.
Events
One solution I have found is leveraging events. By putting something like this in the plugin body:
elem.addEventListener('init', function() {
changeColor.init(elem);
}, false);
anybody will be able to just create an event an fire it accordingly. An example in this case:
var event = new CustomEvent('init', {});
span.dispatchEvent(event);
This would re-init the plugin whenever needed. A working fiddle is to be found here:
http://jsfiddle.net/gleezer/tgztjdzL/1/
The question (finally)
My question is: is there a cleaner/better way of handling this?
How can i let people using this plugin without the need of a global or having to initialise the script themselves the first time? Is event the best way or am I missing some more obvious/better solutions?
You can override Element.setAttribute to trigger your plugin:
var oldSetAttribute = Element.prototype.setAttribute;
Element.prototype.setAttribute = function(name, value) {
oldSetAttribute.call(this, name, value);
if (name === 'data-color') {
changeColor.init(this);
}
}
Pros:
User does not have to explicitly re-initialize the plugin. It will happen automatically when required.
Cons:
This will, of course, only work if the user changes data-color attributes using setAttribute, and not if they create new DOM elements using innerHTML or via some other approach.
Modifying host object prototypes is considered bad practice by many, and for good reasons. Use at your own risk.

Functionally test that an Element is visible (no elements covering) with Intern

I am currently using the JavaScript framework Intern to test my site, I am wanting to ensure that specific element's are truly visible. Intern currently has an option "isDisplayed" which half does this. But what I am wanting to also do is check that it would be truly visible to the user and that any other elements on the page do not cover (perhaps by z-index issues) etc.
Does anyone have an suggestions?
Thanks in advance.
Usually, it's better to focus on your unit tests and make sure the styles you expect to be setting are coming back correctly from the utility/helper functions you use to do so. Otherwise, you're going to end up testing things you probably don't mean to, such as functionality of the browser itself to compute the styles. Therefor, it's bad practice in many situations.
However, if you do need this, such as when testing a 3rd party JavaScript library against a customer's site, Intern's Leadfoot provides a .execute() method you'll want to use.
Example:
return this.remote // represents the browser
.get('mysite.com') // navigate to a page
.execute( // send a callback to the browser
function (selector) {
var elem = document.querySelector(selector),
result;
// collect some data for analysis...
result = getComputedStyle(elem).zIndex;
return result;
},
['div'] // arguments to send to the remote callback
)
.then(
function (zIndex) {
// analyze the data and make assertions about it...
assert(zIndex > 999);
}
);
Please note: This is awesome but be careful. Most of your test runs inside of Node.js, but the callback to .execute() does not and so it does not have access to any of your previously defined variables, etc.
As for strategies to determine when an element is truly visible to the user, it's very subjective, but getBoundingClientRect() is going to be your friend for determining when one element is overlapping another. There are good techniques here: Determine visibility / real z-index of html elements

A JavaScript concatenator to help data hiding under modularization?

I previously run into the problems of data hiding under modularization in JavaScript. Please see the links below:
Module pattern- How to split the code for one module into different js files?
JavaScript - extract out function while keeping it private
To illustrate the problem, see the example below. My goal is to split my long js file into 2 files, but some functions need to access some private variables:
first.js:
(function(context) {
var parentPrivate = 'parentPrivate';
})(window.myGlobalNamespace);
second.js:
(function(context) {
this.childFunction = console.log('trying to access parent private field: ' + parentPriavte);
}(window.myGlobalNamespace.subNamspace);
Now this wouldn't work because child doesn't have access to parent. One solution is to make parentPrivate publicly visible, but that is unacceptable in my case.
Quoting #Louis who gave an answer for one of the previous questions:
"We can't have a field that's accessible by child but not to outside
public (i.e. protected). Is there any way to achieve that?"
If you want modularization (i.e. you want the child to be coded
separately from the parent), I do not believe this is possible in
JavaScript. It would be possible to have child and parent operate in
the same closure but then this would not be modular. This is true with
or without RequireJS.
The problem is that the parent and the child are not inside the same closure. Therefore I'm thinking, does it make sense to create a library that puts files into the same closure?
Something like:
concatenator.putIntoOneClosure(["public/js/first.js", "public/js/second.js"]);
Of course we can take in more arguments to specify namespaces etc. Note that it is not the same functionality we get from RequireJS. RequireJS achieves modularization while this concatenator focuses on data hiding under the condition of modularization.
So does any of the above make sense? Or am I missing out some important points? Any thoughts are welcomed.
If you need things available in two separate files, then you can't have true privacy... however, something similar to this may work for you:
first.js:
(function(context) {
var sharedProperties = {
sharedProp1: "This is shared"
};
function alertSharedProp1() {
alert (sharedProperties.sharedProp1)
}
window[context] = {
sharedProperties: sharedProperties,
alertSharedProp1: alertSharedProp1
};
})("myGlobalNamespace");
second.js:
(function(parent, context) {
// CHANGED: `this` doesn't do what you think it does here.
var childFunction = function() {
console.log('trying to access parent private field: ' + window.myGlobalNamespace.sharedProperties.sharedProp1);
};
window[parent][context] = {
childFunction: childFunction
};
}("myGlobalNamespace", "subNamspace"));
window.myGlobalNamespace.subNamspace.childFunction();
Edit detailed answer based on comments
What I did was to set up a source file that looked like this:
master.js
(function() {
##include: file1.js##
##include: file2.js##
}());
Then I wrote a script (in windows scripting, in my case) that read in master.js and then read through line by line looking for the ##include: filename.js## lines. When it found such a line it read in the include file and just dumped it out.
My particular needs were special since I was writing a browser plugin that needed to work in three different browsers and had to be wrapped up separately, yet for my own sanity I wanted separate files to work with.

Make RequireJS place class on script tags it creates?

I've noticed that RequireJS creates script tags in the tag as it loads modules.
Is there anyway to configure RequireJS to "tag" those elements w/ a class or an attribute of some kind that I could later target w/ jQuery later on?
e.g.:
var $requireJsScripts = $('script.require-script');
--UPDATE--
Ok.. I think I can get by on this little workaround for now. Thanks to this answer for the breadcrumb on require.s.contexts._.defined. I'd still like to hear if anyone knows of a way to configure RequireJS to do something similar to what was laid out in the original question...
var loadedRjsModules = Object.keys(require.s.contexts._.defined);
var $scripts = $('script');
$scripts.each(function () {
if ($(this).data('requiremodule') && $.inArray($(this).data('requiremodule'), loadedRjsModules)) {
console.log(this);
}
});
Looking at the source code, I don't see how RequireJS would allow adding anything custom to the script nodes at creation. The routine that creates them has no provision for it. The code that fleshes them out upon creation does not support it either.
There's an onResourceLoad hook considered part of the internal API. It could be used with the code you've put in your question instead of relying on require.s.contexts._.defined, which as far as I know is fully private and subject to change without notice.

Categories