I have a component y which uses directive :
<div makeDroppable (dropped)="getDroppedList($event)">
<ul>
<li *ngFor="let task of toAddList" >{{task.id}}</li>
</ul>
</div>
at the end of directives MakeDroppable , an event is emit
let data = JSON.parse(ev.dataTransfer.getData('text'));
this.dropped.emit(data);
this event is treated by (dropped)="getDroppedList($event)" (in div) and thus calls getDroppedList of my component.
in this getDroppedList méthod, another event is emit
this.toAddList = <Array<Task>>event;
console.log('emity event');
this.toto.emit(this.toAddList);
this new event toto is used in another component x where html is
<tr *ngFor="let task of tasks" (toto)="removeDroppedList($event)">
removeDroppedList is a method defined in x
removeDroppedList(event){
console.log('this second event')
when i execute code, the second event does not seem to be treated because the 'this second event' is never displayed in console.
i put a breakpoint at console.log('this second event'), but
it never stops
Missing " after tasks in your template.
Assuming the missing " isn't relevant, is there a disconnect with the todo event? What I mean is, are there more than one todo object being created? How does component Y have reference to component X's todo event?
Seems like you need a service so both components have reference to the same event object as component X would need to have that as an output and component Y would get it's reference from the service so it can emit a value.
Related
I have a EditParentAndChildren screen where I want a test that:
navigates to page
remembers the name of the parent
pick one of the children rows
remember its id/name
delete it via the Trashcan button on that row
save
navigate to a View
ensure the parent's name appears and the deleted child's name does not
I can't seem to pluck text off of the screen and put it into one of Cypress's #alias variables, and standard js variables aren't allowed by cypress. So, I use .then to get the value that way.
But when I choose a child row and go .within to get its name and click its delete button, I can't then issue the final assertions for the test because I'm still in the .within, I can't escape the .within because the .then for getting the child's name is completely inside, and, trying to .root().closest() doesn't work because the <tr> I'm in is not only getting deleted but I'm doing a page nav afterward.
cy.get('[name=parentname]')
.invoke('val')
.then(parentName => {
cy.get('[class^=childrenTable]')
.find('[name=child_id]')
.first()
.parents('tr')
.within(tr => {
cy.get('[name=child_id]')
.invoke('val')
.then(nameOfchildToDelete => {
// delete this child
cy.get('[class*=trash]').click();
cy.get(loadingSpinner).should('not.exist');
// ERROR can't find submit button, you are still .within the <tr>
cy.contains(/Submit/i).click();
cy.url().should('match', /parent\/\d+$/);
cy.get(loadingSpinner).should('not.exist');
cy.contains('[class*=breadcrumb_currentcrumb]', parentName).should('exist');
cy.contains('table', nameOfChildToDelete).should('not.exist');
});
});
});
One solution is simply never to use .within. Formerly I was selecting the row, then within it selecting & using each piece of the row. Instead, select each piece of a row using the same selector that selects that row.
Not this:
cy.get('[class^=childrenTable]')
.find('[name=child_id]')
.first()
.parents('tr')
.within(tr => {
cy.get('[name=child_id]')
.invoke('val')
.then(nameOfchildToDelete => {
More like this:
cy.get('[class^=childrenTable] [name=sample_id]:first-child')
.invoke('val')
.then(nameOfSampleToDelete => {
// etc...
cy.get('[class^=childrenTable] [class*=trash]').first().click();
Code inside a .then is just like outside the .then excepting the level of indent, so most of the code is the same. But code inside a .within is kind of at a dead-end. You can't return values from a .within and can't set state or js vars from the outer context.
So: don't use .within, always use long selectors, and don't worry about picking "sections" like a particular <tr> or a particular card in a FlexBox for re-use.
If the selectors are very long consider moving them to a const string outside of the file and possibly concatting them if need be. But generally in Cypress trying to enter into a context is something of an anti-pattern.
So I'm working at a co. as a summer intern and have been tasked with writing tests for their application in cypress.
The application extensively uses shadow DOMs and nested shadow DOMs even. I used the includeShadowDom property true to traverse more easily. But I am facing an issue.
I need to type in 2 input boxes having the same ID and same class but they are in separate shadows. Is there a way I can distinguish between them i.e First occurrence of element with id= and nth occurrence of element with id=?
I can't share any code because it goes against company policy
Assuming you have added includeShadowDom: true in your cypress config file then you can use the eq method to get the respective elements.
E.g. eq(0) for first occurrence of the element, eq(1) for the second and so on.
So your code should look like this:
cy.get('input').eq(0).type('some text')
First possible solution is to select every input with class = something and loop over each.
let words = ['First input', 'second input']
cy.get(`input[class="something"]) // this returns x number of Inputs
.each( ($el, index) => {
cy.get($el)
.type(words[index])
})
Second possible solution is to target the parent element incasing the single input.
cy.get('table') //I don't know what is incasing your inputs but lets assume its a table
.within( () => {
cy.get(`input[class="something"`] //trying to get this to return 1 element
.type('words')
})
Without seeing your HTML markup I can't offer up a more exact solutions. Hope this helps. Look up parent() and parentsUntil() cypress commands if you try the second option.
With inputs there's usually some text that allows the user to distinguish them.
Try targeting the input label or placeholder text, finding the input with "Traversal" commands.
<div>
<label>User name</label>
<input type="text" placeholder="Enter user name" />
<div>
Some basic approaches:
cy.contains('label', 'User name')
.next() // move to next element in the DOM
.type('something')
cy.contains('div', 'User name') // go to common parent of label and input
.find('input') // gives just the input inside parent
.type('something')
cy.get('input[placeholder="Enter user name"]') // use unique placeholder attribute
.type('something')
With shadow DOM be aware you can configure it in the test header
it('searches inside all shadow dom roots', {includeShadowDom: true}, () => {
...
})
The problem is that in svelte on:click triggers on page load for some reason. Can anybody explain to me why it's happening and how to prevent it so it only triggers when you actually check the box. This only happens if on:click is inside each block.
<script>
function handleClick(number) {
alert(number)
}
let numbers = [1,2,3,4,5,6]
</script>
{#each numbers as number}
<input type=checkbox on:click={handleClick(number)}>
{/each}
You can look at it here
The value of on:click should be a function. You're invoking a function — it's no different from doing something like this...
<p>{a} + {b} = {sum(a, b)}</p>
...which, as you'd expect, prints the result of calling the sum function.
Instead, do this:
<input type=checkbox on:click={() => handleClick(number)}>
I want to make 3 dependents drop down list, each drop down dependent to the previous drop down, so when I select an item from first drop down , all data fetch from database and add to second drop down as item.
I know how to do this in a normal php page using ajax, but as opencart uses MVC I don't know how can I get the selected value
Basically, you need two things:
(1) Handling list changes
Add an event handler to each list that gets its selected value when it changes (the part that you already know), detailed tutorial here in case someone needed it
Just a suggestion (for code optimization), instead of associating a separate JS function to each list and repeating the code, you can write the function once, pass it the ID of the changing list along with the ID of the depending list and use it anywhere.
Your HTML should look like
<select id="list1" onchange="populateList('list1', 'list2')">
...
</select>
<select id="list2" onchange="populateList('list2', 'list3')">
...
</select>
<select id="list3">
...
</select>
and your JS
function populateList(listID, depListID)
{
// get the value of the changed list thorugh fetching the elment with ID "listID"
var listValue = ...
// get the values to be set in the depending list through AJAX
var depListValues = ...
// populate the depending list (element with ID "depListID")
}
(2) Populating the depending list
Send the value through AJAX to the appropriate PHP function and get the values back to update the depending list (the part you are asking for), AJAX detailed tutorial here
open cart uses the front controller design patter for routing, the URL always looks like: bla bla bla.bla/index.php?route=x/y/z&other parameters, x = folder name that contains a set of class files, y = file name that contains a specific class, z = the function to be called in that class (if omitted, index() will be called)
So the answer for your question is:
(Step 1) Use the following URL in your AJAX request:
index.php?route=common/home/populateList
(Step 2) Open the file <OC_ROOT>/catalog/controller/common/home.php , you will find class ControllerCommonHome, add a new function with the name populateList and add your logic there
(Step 3) To use the database object, I answered that previously here
Note: if you are at the admin side, there is a security token that MUST be present in all links along with the route, use that URL:
index.php?route=common/home/populateList&token=<?php echo $this->session->data['token'] ?> and manipulate the file at the admin folder not the catalog
P.S: Whenever the user changes the selected value in list # i, you should update options in list # i + 1 and reset all the following lists list # i + 2, list # i + 3 ..., so in your case you should always reset the third list when the first list value is changed
P.P.S: A very good guide for OC 1.5.x => here (It can also be used as a reference for OC 2.x with some modifications)
How can i select Ajax Dropdown suggestion list item using selenium code for firefox??
My problem is :the Ajax dropdown list is visible but it is not selected and next steps gets stuck.
May be selenium is waiting for something.
the list that page populates is dynamic and in bla bla tags.
Please help with a example code.
How can i use waitfor* here.
Remember i am not using firefox ide but i am writing a code.
Please help.
I had a similar problem whereby, selenium was able to find the dropdown menu but was unable to click on the visible text. I later found out that there was an Ajax call that was populating the dropdown menu data and as a result selenium seemed to not be able to select the intended visible text because the list items had not been fully populated. That is, by the time the script was selecting my option value, Ajax had not completely loaded the menu options. Here's my solution:
public void nameOfCollegeList(String optionItem) {
// declare the dropdownMenu web element
WebElement dropDownMenu = driver.findElement(By.cssSelector("#CollegeNames"));
// click on the dropdownMenu element to initiate Ajax call
dropDownMenu.click();
// keep checking the drop down menu item list until you find the desired text that indicates that the menu has
// been fully loaded. In this example I always expect "Other (please specify)" to be the last item in the drop down menu.
// If I don't find the expected last item in the list in my if condition, execute the else condition by calling the
// same method(recursively). Please note that if the "if" statement is never satisfied then you'll end up with an
// infinite loop.
if (dropDownMenu.getText().contains("Other (please specify)")) {
new Select(dropDownMenu).selectByVisibleText(optionItem);
}
else {
nameOfCollegeList(optionItem);
}
}
i am little confused with your question at " :the Ajax dropdown list is visible but it is not selected "
this sounds like that the element is disabled. (Java coding)
if so selenium.isElementDisabled()
if not then,
1) programming laguage solution using while loop and isElementPresent() OR isElementDisabled()
//trigger the Ajax request and then
long initialTime = System.currentTimeMillis();
do{
thread.sleep(1000);
}while((!selenium.isElementPresent("AjaxElement")) && (System.getCurrentTimeMillis() - initialTime <= 5000)) ;
//some thing like above for client programming solution...but for,
2) selenium's inbuilt solution
we have a method called waitForCondition("java script to be executed", "time out value");
this method loops the javascript statement until it returns true or the supplied time out occurs
here the important thing is analyzing the application/Ajax element to find out which particular condition of the element changes.
from your explation my guess is this, display=none will be changed to display=block OR
disabled=true will be changed to disabled=false OR isReadOnly will be changed to no such attribute ect.....(you need to figure out this)
and then, use this attribute = value to build a javascript function as ,
selenium.waitForCondition("window.document.getElementById('AJAX ELEMENT').disabled == 'false'", "3000");
you can work out the above statement however you want in your programming language.
try {
//do the action which triggers the Ajax call
selenium.waitForCondition("window.document.getElementById('AJAX ELEMENT[drop down element]').disabled == 'false'", "3000");
//OR
selenium.waitForCondition("window.document.getElementById('AJAX ELEMENT').disabled == 'false'", "3000");
}
catch(SeleniumException se)
{
if((se.getMessage()).toLowerCase().contains("timed out")
throw //..some a custom exception however your organisation requires
}
selenium.select("drop down element id", "option id");
and so on.....