I'm trying to prove that in a table we have the following table labels. Date, amount, comment.
<table class="grid-table-body">
<thead>
<tr>
<th>Date</th>
<th>Amount (£)</th>
<th>Description</th>
</tr>
</thead>
<tbody>
.....
.....
.....
</tbody>
</table>
I've got as far as proving the table is present!
var myTable = element(by.css('.grid-table-body'));
expect(myTable.isPresent()).toBeTruthy();
How can I loop through each <th> and get the text. If I was just to put them into an array I could prove they are what they should be. i.e.
expect(data.get(0).getText()).toBe("Date");
Would be enough (I think)
First locate the elements, then you can call getText():
var headers = $$(".grid-table-body thead th");
expect(headers.getText()).toEqual(["Date", "Amount (£)", "Description"]);
To check that all of the headers are visible, you can either use:
expect(headers.isDisplayed()).toEqual([true, true, true]);
Or, check if there is no false in the array:
expect(headers.isDisplayed()).not.toContain(false);
You can also map()/reduce() it to a single boolean value.
Related
For the starters, I would like to have something like this,
Array 1 Array 2 Array 3 Array 4
Arr1val1 Arr2val1 Arr3val1 Arr4val1
Arr1val2 Arr2val2 Arr3val2 Arr4val2
Arr1val3 Arr3val3 Arr4val3
Arr1val4 Arr4val4
Arr4val5
I have already solved the issue in the crudest way possible,a solution that won't scale to other data types and if number of variable increase to lets say 10 columns it will fail in the most glorious way which makes me cringe and ask for suggestions of improvement.
My naive approach is here in a fiddle.
As the code is simple I would like to explain what I did.
Step 1 : Calculate the highest number of elements in all arrays and the array from which it is coming.
Step 2 : Make the number of elements in all array same as the number of elements in the highest number of element possible by filling in blanks.
Step 3 : Iterate over one in the HTML and print all.
Would like to know what can be done to make this solution better and more scalable?
Instead of finding max length of arrays, push all the values to the specific array.
Draw a table inside the td. So here the data are drawn vertically.
Using this scenario, you can add any number of data to any array, since
this is generating vertically.
Please see the working code
https://jsfiddle.net/yaxmjpkp/7/
var app = angular.module('myApp', []);
app.controller('myController', function($scope) {
//Test case 1
$scope.arr1 = ["Arr1val1", "Arr1val2", "Arr1val3", "Arr1val4"];
$scope.arr2 = ["Arr2val1", "Arr2val2"];
$scope.arr3 = ["Arr3val1", "Arr3val2", "Arr3val3"];
$scope.arr4 = ["Arr4val1", "Arr4val2", "Arr4val3", "Arr4val4", "Arr4val5","Arrayval6"];
$scope.tableValues=[];
$scope.tableValues.push($scope.arr1);
$scope.tableValues.push($scope.arr2);
$scope.tableValues.push($scope.arr3);
$scope.tableValues.push($scope.arr4);
debugger
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myController">
<table>
<thead>
<td>
Header 1
</td>
<td>
Header 2
</td>
<td>
Header 3
</td>
<td>
Header 4
</td>
</thead>
<tbody>
<tr>
<td ng-repeat="val in tableValues" valign = "top">
<table>
<tr ng-repeat="val2 in val">
<td>{{val2}}</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
</div>
</div>
As far as I know you don't need to do the first two steps. As javascript is loosely typed language and so is angular (although its not a language but its built over JS). So when you access some value like
<tr ng-repeat="val in arr1 track by $index">
<td>{{arr1[$index]}}</td>
<td>{{arr2[$index]}}</td>
<td>{{arr3[$index]}}</td>
<td>{{arr4[$index]}}</td>
</tr>
Angular won't find any element on that index (Because of the unequal size of that array). So you won't have any issue regarding the access of the value on that particular index. And an empty <td> will be added in that place.
Btw, you can store array elements in associative array and you can check max length in a more generic way.
$scope.arrs = {
arr1: ["Arr1val1", "Arr1val2", "Arr1val3", "Arr1val4"],
arr2: ["Arr2val1", "Arr2val2"],
arr3: ["Arr3val1", "Arr3val2", "Arr3val3"],
arr4: ["Arr4val1", "Arr4val2", "Arr4val3", "Arr4val4", "Arr4val5"]
};
var maxLength = 0;
for(var arrKey in $scope.arrs){
maxLength = Math.max($scope.arrs[arrKey].length, maxLength);
});
Here is complete solution: https://plnkr.co/edit/p6EcXeiRKHY2wQA3xCi4?p=preview
I am trying to delete an entity from the Datastore using a link in html. I understand that in order to do this, I need to have the entity's key so that I know which entity to "pair" the delete link with, so to speak. I can't for the life of me figure out how to do this...
Here is my html file that shows all of the cars in the database:
{% if cars|length > 0 %}
{% for c in cars %}
<tr>
<td>{{ c.make }}</td>
<td>{{ c.model }}</td>
<td>{{ c.year }}</td>
<td>
{% for i in c.color %}
{{ i }}
{% endfor %}
</td>
<td>{{ c.condition }}</td>
<td>{{ c.date }}</td>
<td>
Delete Car
</td>
</tr>
{% endfor %}
{% endif %}
Here is the python file:
class AddCarHandler(webapp2.RequestHandler):
template_variables = {}
def get(self):
template = JINJA_ENVIRONMENT.get_template('index.html')
self.response.write(template.render(self.template_variables))
action = self.request.get('action')
#if the user adds a car
if action == 'add_car':
c = car_database.Car()
c.make = self.request.get('car-make')
c.model = self.request.get('car-model')
c.year = self.request.get('car-year')
c.color = self.request.get_all('car-color')
c.condition = self.request.get('car-condition')
c.date = self.request.get('car-date')
car_key = c.put()
class ViewCarHandler(webapp2.RequestHandler):
template_variables = {}
def get(self):
car = car_database.Car()
#ndb query
self.template_variables['cars'] = [{'make':x.make, 'model':x.model, 'year':x.year, 'color':x.color, 'condition':x.condition, 'date':x.date} for x in car_database.Car.query().fetch()]
template = JINJA_ENVIRONMENT.get_template('/view_cars.html')
self.response.write(template.render(self.template_variables))
You can get the key of an entity (which, say, is obtained through a query) like this:
entity_key = entity.key
Note: this only works after the entity was saved into the DB, not before (i.e. entity.put() was called at least once).
To pass the key between the python code and URLs or HTML code, from the documentation, you can use a key's url string or a pre-computed deletion url based on that string, passed, for example, in self.template_variables['cars']:
You can also use an entity's key to obtain an encoded string suitable
for embedding in a URL:
url_string = sandy_key.urlsafe()
This produces a result like agVoZWxsb3IPCxIHQWNjb3VudBiZiwIM which can
later be used to reconstruct the key and retrieve the original entity:
sandy_key = ndb.Key(urlsafe=url_string)
sandy = sandy_key.get()
You'll need to add a handler for such deletion url, in which you'd reconstruct the key as quoted above, then call:
entity_key.delete()
I'm having a hard time getting the result that I'm looking for. Here is an image of my table row.
The final column (the one circled in blue) is support to count that mini-tables (Quantity - Allocated - Reserved) then subtracts the number in orange (in this case -4).
I can get the first row to work (for example, it shows 1, which is correct). But the second row should be accumulative, so that it adds the blue number from the previous row. I'm not sure how to accomplish this in Angular.
This is my view template:
<tr ng-repeat="inbound in inventory.inbound">
<td><% inbound.fordate %></td>
<td><% inbound.quantity %></td>
<td><% inbound.allocated %></td>
<td><input type="number" ng-model="inbound.reserved" ng-change="submitChangedInbound()" class="inbound_reserved"></td>
<td><span class="label round" ><% availableAfterShipment() %></span</td>
</tr>
and this is my function:
$scope.availableAfterShipment = function(amount) {
return $scope.dealerAvailable + this.inbound.quantity - this.inbound.allocated - this.inbound.reserved;
};
Thanks in advance for reading. I am trying to utilize angular's ng-repeat to render objects from an array into an Nx3 Table. For the sake of example let's consider a 3x3 table.
Here is a simplified example of the array:
objects = [{"text": "One, One"},{"text": "One, Two"},{"text": "One, Three"},
{"text": "Two, One"},{"text": "Two, Two"},{"text": "Two, Three"},
{"text": "Three, One"},{"text": "Three, Two"},{"text": "Three, Three"}];
The "text" field describes where in the 3x3 grid matrix each element should appear. I would like to use ng-repeat on objects to generate html that looks like this:
<table>
<tr>
<td>One, One</td>
<td>One, Two</td>
<td>One, Three</td>
</tr>
<tr>
<td>Two, One</td>
<td>Two, Two</td>
<td>Two, Three</td>
</tr>
<tr>
<td>Three, One</td>
<td>Three, Two</td>
<td>Three, Three</td>
</tr>
</table>
Is there any way to achieve this without needing to break up the array into separate arrays for each row?
Best possibly way would be to alter your view model in the controller and bind that to ng-repeat (But you already said you do not want to do that). If you ever plan to take that route you can also take a look at user #m59 answer where he creates a reusable filter to do it. However this is just a simple answer making use of built in filter's configurable evaluation expression where we can return truthy/falsy value to determine if they need to be repeated or not. This eventually has the only advantage of no need to create 2 ng-repeat blocks (But that is not so bad though). So in your controller add a function on the scope,
$scope.getFiltered= function(obj, idx){
//Set a property on the item being repeated with its actual index
//return true only for every 1st item in 3 items
return !((obj._index = idx) % 3);
}
and in your view apply the filter:
<tr ng-repeat="obj in objects | filter:getFiltered">
<!-- Current item, i.e first of every third item -->
<td>{{obj.text}}</td>
<!-- based on the _index property display the next 2 items (which have been already filtered out) -->
<td>{{objects[obj._index+1].text}}</td>
<td>{{objects[obj._index+2].text}}</td>
</tr>
Plnkr
I wanted to do the exact same thing.
Convert an array into a matrix/ grid
I have an array which i wanted to convert into a grid/matrix of column size 4. the following implementation worked for me. You can use the two counters : row and col as you like in side the nested ng-repeat
In my case number of columns is 3. But you can replace that 3 with a variable everywhere. h.seats is my array of the objects and i want to print either X or - based on value of element in that array
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th ng-repeat="n in [].constructor(3 + 1) track by $index">{{$index}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="(row, y) in getNumber(h.seats.length, 3) track by $index">
<td>{{row+1}}</td>
<td class="text-primary"
ng-repeat="(col, t) in h.seats track by $index"
ng-if="col >= (row)*3 && col < (row+1)*3">
<span ng-show="t.status"> X </span>
<span ng-show="!t.status"> - </span>
</td>
</tr>
</tbody>
</table>
</div>
<th ng-repeat="n in [].constructor(3 + 1) track by $index">{{$index}}</th> prints the header row with column number at the top. getNumber(h.seats.length, 3) returns me the number of rows of that table as follows
.controller('CustomViewController', function ($scope, Principal, $state) {
$scope.getNumber = function(length, columns) {
return new Array(parseInt(length / columns + 1, 10));
}
The line ng-if="col >= (row)*3 && col < (row+1)*3" is important logic to calculate which elements should be put in that row.
The output looks like below
0 1 2 3
1 e1 e2 e3
2 e4 e5 e6
3 e7 e8
Refer to following link for details of how row and col counters are used:
https://stackoverflow.com/a/35566132/5076414
My html code is:
enter code here:
<table>
<tbody>
<tr>
<td class="item item-selected" id="gwt-uid-537" role="menuitem">Test Customer 1<br>#34</td>
</tr>
<tr>
<td class="item" id="gwt-uid-538" role="menuitem">TEST CUSTOMER 2<br>#1,9874563210</td>
</tr>
<tr>
<td class="item" id="gwt-uid-539" role="menuitem">test <br>test</td>
</tr>
</tbody>
</table>
What i want to do is just find the Customer Name (for ex: TEST CUSTOMER 2) before break-line tag and then click on that row.
I have tried as follows:
String ExpCustName = "TEST CUSTOMER 2";
Thread.sleep(1000);
WebElement FindCust = driver.findElement(By.xpath("//div[#class='customer']/table/tbody/tr/td/input[#class='gwt-SuggestBox']"));
FindCust.sendKeys("TES");
List<WebElement> CustList = driver.findElements(By.xpath("//div[#class='suggestPopupMiddleCenterInner suggestPopupContent']//table//tr"));
for(int i=0;i<CustList.size();i++){
String ActCustName = CustList.get(i).getText();
System.out.println(ActCustName);
Thread.sleep(1000);
if(ActCustName.contains(ExpCustName)){
CustList.get(i).click();
}
}
// find the customer table
WebElement table = driver.findElement(By.xpath("//div[#class='customer']/table"));
// find the row
WebElement customer = table.findElement(By.xpath("//tr/td[contains(text(), 'TEST CUSTOMER 2')]"));
// click on the row
customer.click();
You might need to tweak a bit the two xpath expressions to match your specific page.
What i understood from this question is:
List<WebElement> CustList = driver.findElements(By.xpath("//div[#class='suggestPopupMiddleCenterInner suggestPopupContent']//table//tr"));
for(int i=0;i<CustList.size();i++){
String ActCustName = CustList.get(i).getText();
System.out.println(ActCustName);
Thread.sleep(1000);
if(ActCustName.contains(ExpCustName)){
CustList.get(i).click();
}
The above part of code is to click on "TEST CUSTOMER 2"
for that you can use the below statement:
driver.findElement(By.xpath("//div[#class='suggestPopupMiddleCenterInner suggestPopupContent']//table/tbody/tr[./td[text()='TEST CUSTOMER 2']]")).click();
And i am didn't understood is:
WebElement FindCust = driver.findElement(By.xpath("//div[#class='customer']/table/tbody/tr/td/input[#class='gwt-SuggestBox']"));
FindCust.sendKeys("TES");
What is the purpose of above code?
static WebDriver driver = new FirefoxDriver();
private static WebElement findElementByTagAttr(String tagName, String attrName, String attValue)
{
List<WebElement> elements = driver.findElements(By.tagName(tagName));
WebElement elementToFind = null;
for(WebElement element : elements)
{
if(element.getAttribute(attrName).equals(attValue))
{
elementToFind = element;
break;
}
}
return elementToFind;
}
In Ruby, I have found the following to work quite well. First some background - I am using .properties files to host my element IDs and my values (URLs, text field entries, etc), so I needed to insert a value into the middle of my element ID. My solution has been to break up the xpath into two element id pointers this:
driver.find_element(:xpath, $elementIDs["FIRST_PART_OF_XPATH"] + $props["REQUIRED_VALUE"] + $elementIDs["END_OF_XPATH"]).click
It's not pretty, but it is effective. I hope this helps the next Ruby guy looking for a solution.
EDIT: Sorry, I got distracted while writing this. The xpath is //td[contains(., 'Blah')] where Blah is the text provided by $props. My pointer file looks like this:
FIRST_PART_OF_XPATH=//td[contains(., 'END_OF_XPATH=')]
I can readily change the text I'm searching for by editing the $props file with the required text. Like I said, it's not pretty code, but it works a tick.