Intern functional test - iterating on set of items - selenium

This seems trivial, but I'm attempting to set up a functional test in Intern to check the inner text of a set of span elements in my page all with the same CSS class, but I can't seem to be able to isolate the text within the span. Here is my code:
'Span check': function () {
return this.remote
.findAllByClassName('mySpanClass')
.then(function (elems) {
assert.strictEqual(elems[0].innerHTML(),'Span Text');
})
}
I've run separate tests to verify that the spans are being found... the findAllByClassName function returns an array of two Objects.
Anyone done anything like this?

You need to use getVisibleText() instead:
Gets the visible text within the element. elements are converted
to line breaks in the returned text, and whitespace is normalised per
the usual XML/HTML whitespace normalisation rules.
return this.remote
.findByCssSelector('.mySpanClass')
.getVisibleText()
.then(function (text) {
assert.strictEqual(text, 'Span Text');
});
This would work for a single element.
If you want to check the text of each span, use:
return this.remote
.findAllByCssSelector('.mySpanClass')
.getVisibleText()
.then(function (texts) {
assert.strictEqual(texts, ['Span1 Text', 'Span2 Text']);
});

Related

How to write Testcafe selector('Withoutvalue').withText('Valid Text')?

I am facing a scenario where the element tag name and attribute is changing from env to env, but the text content alone is unique.
Therefore I am not able to define any value for Selector('could not define anything here').
How could I write a path to locate the element ?
I don't see a direct solution for this, but a workaround that could solve your issue. You could have an object that holds environments specific data for you and which helps you for specific cases as the one that you seem to be confronted with. In this object, you could also store environment specific Selectors. This could, written in TypeScript, look as follows:
import { Selector } from "testcafe";
interface EnvironmentData {
envName: string;
myVariableSelector: Selector;
}
// Set up a list that contains environment specific data objects
const CONFIGS: EnvironmentData[] = [
{
envName: "MyEnv1",
myVariableSelector: Selector("my css selector 1").withText("my text 1")
},
{
envName: "MyEnv2",
myVariableSelector: Selector("my css selector 2").withText("my text 2")
},
{
envName: "MyEnv3",
myVariableSelector: Selector("my css selector 3").withText("my text 3")
}
]
// Assuming that you're CI for instance sets a environment variable ENVIRONMENT_NAME to
// any of the specific environments MyEnv1, MyEnv2 or MyEnv3
function getConfigForEnvironment(envDataSets: EnvironmentData[]): EnvironmentData {
const envData = envDataSets.find((c) => c.envName === process.env.ENVIRONMENT_NAME);
if (envData === undefined) {
console.error(`No suitable data for environment '${process.env.ENVIRONMENT_NAME}' found!`);
process.exit(1);
}
return envData;
}
// Determine the right object before the tests start
const envData = getConfigForEnvironment(CONFIGS);
fixture`My awesome tests`.page("myTestUrl");
test("My test", async (t) => {
// Make use of the object that holds the data for the desired environment
await t.expect(envData.myVariableSelector.exists).ok("Should be fine for any environment!");
});
I did it in a simpler way using the or operator (,)
i,e I wrote the selector with Selector('div,span').withText('Value')
The attribute div and span are changing with environment so I used , to pass both and it worked.

Space character doesn't get recognized in lodash's debounce method with b-taginput in buefy?

I am using buefy's b-taginput with lodash's debounce method to fetch data from an api source during the #typing event. The issue is when I hit spacebar in the input field , inside the debounce method the input character is not recognized as an actual character.
<b-field label="Roles">
<b-taginput
:value="this.objectData.roles"
:data="filteredTags"
autocomplete
field="role"
icon="label"
placeholder="add role..."
#focus="getAsyncRole"
#typing="getAsyncRole"
#input="(newValue) => {updateValue(newValue, 'roles')}"
>
<template slot-scope="props">
<p>{{props.option.role}}</p>
</template>
<template slot="empty">There are no items</template>
</b-taginput>
</b-field>
getAsyncRole: debounce(function(name) {
console.log('inside getAsyncRole and name.length is '+name.length) // the length is 0 when i hit
spacebar but why?
if (!name.length) {
this.filteredTags = [];
return; //exits the function if length of input is zero
}
this.isFetching = true;
api
.getSearchData(this.sessionData.key,`/role/?filter={role} LIKE '%25${name}%25'`)
.then(response => {
console.log('response for getasync role is'+JSON.stringify(response))
this.filteredTags = [];
response.forEach(item => {
this.filteredTags.push(item);
});
})
.catch(error => {
this.filteredTags = [];
throw error;
})
.finally(() => {
this.isFetching = false;
});
}, 500),
The above mentioned code works if I type any alphabetic character (i.e. it give's me the possible autocomplete results based on input character). But I also want it to list out all the autocomplete results (total results) when I hit spacebar into the b-taginput. Since it doesn't recognize the space character as an actual character, name.length become zero, and then it exits the function without making the api call.
NOTE: I noticed that this issue occurs only for b-taginput. This issue does not occur in the case of <b-autocomplete>. With <b-autocomplete> if I hit spacebar then I get all the results as desired. Therefore, I think this issue is specific only to b-taginput. Please help by advising a workaround for this.
The source code indicates that #typing trims the input before emitting it. This leaves a couple options, the best one (by far) is to pre-fetch the unfiltered list. With the list in hand, you can filter exactly as the example code does, searching for the input string within the list.
(The example code works because the empty string '' emitted by typing a space is "found" in every string)
Think about this: you're debouncing the API because you're concerned about hitting it too hard. Drop the debounce and just hit it once. Worried that fetching all tags is too long to wait? Just wait once and never wait again (consider that you were willing to incur this wait on every blank input).

Cypress Get Attribute value and store in Variable

I want to get the Attribute value and store in a variable how we can achieve this in cypress
In my case I want to get the complete class value and store it in variable.
This code just give me the attribute class value but how I can store the fetch value in variable
cy.get('div[class*="ui-growl-item-container ui-state-highlight ui-corner-all ui-shadow ui-growl-message"]').invoke('attr', 'class')
I was trying to compare the style of one element with another to make sure they were equal. Here's the code that seems to work for me.
cy.get('.searchable-group-selector-card-image')
.eq(4)
.invoke('attr', 'style')
.then(($style1) => {
const style1 = $style1
})
A good way to solve this kind of scenario is to use the alias mechanism. One could leverage this functionality to enqueue multiple elements and then check all of them together by chaining the results. I've recently come to a case in an SPA where the assertion had to happen between elements that were spread across different angular routes (call them different pages).
In your use case, this would like:
cy.get('.searchable-group-selector-card-image')
.eq(4)
.invoke('attr', 'style')
.as('style_1')
cy.get('.another-element')
.invoke('attr', 'style')
.as('style_2')
// later on for example you could do
cy.get('#style_1').then(style_1 => {
cy.get('#style_2').then(style_2 => {
// Both values are available and any kind of assertion can be performed
expect(style_1).to.include(style_2)
});
});
This is described in Variables and Aliases section of the Cypress Documentation.
Here is how I got the value of for attribute in a label tag which had text "Eat" inside.
cy.contains('Eat').then(($label) => {
const id = $label.attr('for');
}
Most important thing is to get the selector right, so it exactly finds the value you are looking for. In this case you already found it. By using then() gives you the ability to store it in a variable.
cy.get('div[class*="ui-growl-item-container ui-state-highlight ui-corner-all ui-shadow ui-growl-message"]').invoke('attr', 'class')
.then($growl-message => {
const message = $growl-message.text()
//do the checks with the variable message. For example:
cy.contains(message)
})
Note that the scope of the variable is within the curly brackets. Thus using the variable has to be within those curly brackets.

Why evaluate() in Protractor?

When I run the below snippet, I got the following output. But I'm still unclear why and when evaluate() has to used ....
browser.get('https://weather.com/en-IN');
$$("input[data-ng-change='goSearch()']").evaluate('placeholderText').then(function(value) {
console.log(value);
});
evaluate() is rarely used, but has a unique purpose - it gives you an access to the scope of the current element you are working with. This is usually needed when a value you are looking for is not exposed in the HTML as an attribute or element's text.
For example, when you have a repeater over an array of objects and you need to access some object property that is not in the HTML:
element.all(by.repeater("address in addresses")).filter(function (elm) {
return elm.evaluate("address.zipCode").then(function (zipCode) {
return zipCode === "10801";
});
});

How to programatically add and use elements (dialog box in this case)

So My first though was, that adding more, and more HTML elements is not a way to go, and I come up with this solution
var Jaxi = {
CurrentLocation: '/',
showLoginDialog: function () {
dojo.place('<div data-dojo-type="dijit.Dialog" style="width:600px;" id="loginDialog"><div id="dialog-content"></div><a href="javascript:Jaxi.CloseDialog()">Close</div>', dojo.body())
dojo.xhrGet({
url: "/Account/SingIn?ReturnUrl=" + Jaxi.CurrentLocation,
load: function (result) {
dojo.byId("dialog-content").innerHTML = result;
}
});
dojo.ready(function () {
dijit.byId("loginDialog").show();
});
},
CloseDialog: function () {
dijit.byId("loginDialog").hide();
dojo.destroy("loginDialog");
}
};
It's working.. To some degree at least. Dialog open, but no styles are appiled. But moreover I can't close dialog.
Question Is how to make it working ?
After you have placed the div in your body, Dojo needs to parse the HTML to "notice" the new widget. When it notices the data-dojo-type attribute it says "Hey, here's a widget, I need to make this into a beautiful Dialog".
showLoginDialog: function () {
dojo.place('<div data-dojo-type="dijit.Dialog" ....</div>', dojo.body());
dojo.parser.parse();
....
Of course, you also have to make sure your body tag has class="claro" (or any other theme you want to use).
That being said, I personally think this is a little messy way to make a dialog box. You are sort of mixing declarative with programmatic. I'm not sure what you mean by "My first though was, that adding more, and more HTML elements is not a way to go", but in my own opinion mixing HTML inside your javascript makes the code difficult to read. You may want to take a look at this sitepen article if you want a clean way to separate HTML and Javascript.