How to select nth element in codeception - php

I have a table with checkboxes in each row. The user can select some rows and delete them, also I have this "select all" checkbox.
I want to test selecting and deleting two rows for example, also click select all and delete them.
So I need to check the second and third checkboxes for the first test and first one for the second test...
I couldn't find a way to select the nth element, the only way I could find is selecting by xpath, so I tried this without luck:
$I->checkOption("(//input[#type='checkbox'])[2]");
The error is smt. like //html(//input[#type='checkbox'])[2] is invalid.
Apparently codeception is modifying the selector, so I tried to use WebDriverBy class but I couldn't find a way to pass it as a parameter...
Any ideas?
PS: This is not the actual case but a simple example to describe the problem...

I found a way to do it from this answer.
This is it:
$I->checkOption("/descendant::input[#type='checkbox'][2]");

This works at my end , you can use this one also
$I->checkOption('[name="published"]');
And for the Question:
we can find nth element in following ways:
$I->click("table#races-table tbody tr:first-child td:last-child button")- Table(if you know first child and last child)
$I->click('#side-menu li:nth-child(2)');- (Side menu you have and need to select item from the sub menu)
$I->selectOption('.radio-tab:nth-child(1)', '1'); -- (Selecting radio button if you have multiple in a form)

Related

Click a button with XPath using an id from the same row

Im currently testing using PHPUnit and i need to create and delete the same things. So i create something called test, i want to be able to find it and delete it. I have multiple Delete buttons on the page, and it works by doing something like this -
$this->click("xpath=(//img[#title='Delete'])[11]");
but by choosing [11] for example, it is only using the delete button from row 11. And if Test isnt Row 11 for example, i will delete something i do not wish to delete.
I wish to try and delete a specific row by finding a row with a certain id attached to it.
The row may have the words "Test" followed by more information within columns. Then a delete button at the end titled 'Delete'. I wish to find the row with the id or words 'Test' and then find and use the 'Delete' title on that row.
Any help?
EDIT -Example image of a row. I would like to grab the first text, and then use the very last button on the right titled 'Delete'
http://i.stack.imgur.com/S4BNE.png
SECOND EDIT - This is the whole table, it contains all of the rows and within the rows it contains the td's (Obviously, as you'd know).
This is where ill find the text im trying to find. This tr would count as the 4th of 6.
This shows the td containing delete, a td containing 'Test Profile' and the whole table itself.
http://i.imgur.com/4r1tsJe.png
TL;DR Essentially, im trying to do, Where td contains 'Test', use 'Delete' from the same row.
Not very clear but I'll try to guess from your comments.
Forget about rows, but let's find all the td with "Test" (or some text you want in it)
descendant::td[contains(.,'Test')]/
and from here select the following-sibling td that contains a delete image
following-sibling::td//img[#title='Delete']
now you have the set of images nodes to click on, for each row.
Of course, if your function
$this->click("xpath=.....");
accepts only one node at the time, one possibility is to put the parenthesis and select always the first node (assuming that your test will delete it)
(descendant::td[contains(.,'Test')]/following-sibling::td//img[#title='Delete'])[1]
Even if the node is deleted when you click on it, in the next test this expression will always match, until there is any node left on the page
This is similar (not perfectly the same) to having a for loop ?
buttons = "xpath=....."
for each b in buttons do {
$this->click(b);
}
hope it helps
If you want to find the first row that contains Test in the first <td> element, or that has an id attribute of "Test" on the <tr> element; and you want to click the Delete img element from that row, you could try
$this->click("xpath=(//tr[#id='Test' or contains(td[1], 'Test')]//img[#title='Delete'])[1]");
But this is somewhat guesswork, since I can't see the HTML you're working with.
Since it looks like 'Test' could be in all-caps or in mixed-case, you may have to build in some case-insensitivity:
$this->click("xpath=(//tr[#id='Test' or
contains(translate(td[1], 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
'TEST')]//img[#title='Delete'])[1]");
Yes it's kludgy, but AFAIK PHP only supports XPath 1.0.

PHP/MySQL Reorder Menu with Position set in table

In MySQL I have a table with a name, id, position, and content values.
The content is loaded onto a page in php by querying by id. The position is used in php to create a dynamic menu with the menu items ascending by position value.
So for example, say There were 3 rows with each row having a position value of 1, 2, or 3.
I am trying to build a form to allow the user to change the position of the menu, items, or add a new one. So if the row in position 3 wants to be changed to position value 1, then 2 needs to become 3 and 1 needs to become 2. Or if a new item is added, the position its taking and all below it need to be shifted up a value.
What would be the best way of approaching this?
Any suggestions would be appreciated.
If you add new item- frst update all items with position value equal or more:
UPDATE MenuItems SET position = position + 1 WHERE position >= newItemPosition;
If you are updating - update only item with position higher than higherItemPosition (they will only switch places).
UPDATE MenuItems SET position = position - 1 WHERE position = higherItemPosition;
If newItemPosition is updated to lower value I would do sth like that:
UPDATE MenuItems SET position = position + 1 WHERE position = lowerItemPosition;
Two ideas come to mind:
have the menu as an AJAX loaded div and then react to the change and reload the div, which means you could rerun the SQL
load the answers into a javascript array and present them that way as you then have drag change abilities.
Before we swarm the database with queries, create indexes (e.g. primary key) that covers the position field, update several rows with their index entries per change, and so on, let's consider the following:
How long would a menu get, in the worst case?
Do you really need to obtain individual rows from the menu, or whenever you need to display a menu you need to SELECT all of its rows?
Most often, these cases can be solved with a much simpler, pragmatic approach that will also be far easier for you as a programmer. If the menu isn't going to be too long and you probably need all of it every time you need to read it, why not keep it as a list (of items of whatever type) in your program, and serialize it with whatever method (e.g. JSON or Python Pickle) before storing it in the database as a single row with a text field? If the menu is in a list, reordering its elements will be pretty simple, a read operation for the menu would demand a single row SELECT for the database, and a write operation would require a single UPDATE, without caring for keeping a Position field updated.

AJAX response from database creates duplicate entries

I am trying to build a simple forum where the questions wil be refreshed automatically . Although it is done ,I have two problems.
1 . Since I retrieve the last update from database,last entry is dulicated.
2 . The div where I put the AJAX response always refrshes .
How can I remove the duplicate entries and make it smooth forum ,just like in facebook comment page ?
If I understand your first problem, you're saying you are doing something like:
Take the user's input (i.e. the new entry)
Write this input to your database
Select all entries, including the one you just added
Because you are also separately adding the new reply to the div client-side or something the last entry always shows up twice (but doesn't get written to the database twice).
If this is the case you could solve the problem by either omitting the last entry from your MySQL query (e.g. SELECT * FROM entries WHERE id != (SELECT MAX(id) FROM entries)) or by simply refraining from processing the entry on the client's side.
Concerning your second problem:
Instead of fetching all entries and replacing all content inside the div with the new list of entries, try only appending the new entry with .innerHTML += ... or jQuery's .append() for example. This way you won't experience any 'flickering' or jumping content with the rest of the replies.

How do i manage M:N Post-Tag relationship (eg. Edit/Delete)

its when i starting trying implementing this that i got quite stuck.
some business rules
1 Post can have many Tags.
1 Tag can have many Posts
the database will look like.
Posts (id, title, body, ...)
Posts_Tags (post, tag)
Tags (id, tag, ...)
when i insert - straightforward
tags will come from user input as comma separated values
explode($tags) to get individual tags
foreach $tag
check if tag exists
if yes, get id
if no, insert tag & get id
insert post with tags
i am wondering if this is the best way? can i do away with the loop to chk if the tags exists? or simplify it into 1 query?
update a post, abit harder
how can i check if the user has updated any tags. another loop? but this time there will be some changes (italic)
explode($tags) to get individual tags
foreach $tag
check if this post has been tagged with this tag
if no,
does tag exists?
yes, get id
no, insert and get id
if yes, get id
update post with tags
hmm, ... update is more confusing, how will u implement this?
i am using PHP 5.3, Zend Framework 1.10, Doctrine 2
I think the post-tags relationship should be many-to-many; ie: posts have and belong to many tags. This can be implemented with a junction table. Here's some literature on the subject. Then...
Insert: Do the same thing you are doing now, except you can fetch all tags in one query :
SELECT name FROM tags WHERE name IN ($tags)
Update: The easy way out: Remove all current tags, insert tags as if they were all new. Or...
$tags = explode(',' $_POST['tags']); // remove whitespaces
# delete all current tags that were not included in the edit
DELETE FROM post_tags WHERE post_id=$post_id AND tag_id NOT IN ($tags)
# find out what the current tags are, use a JOIN to find out their labels
SELECT tag_id FROM post_tags WHERE post_id=$post_id
fetch results, remove found tags from $tags, then
foreach new $tag, insert as if they were new
I do tags pretty similar to how your updated psuedocode is, except for one added step. You need to check to make sure no tags exist for the post that do not are not in the user input. For example if a post is tagged "php,sql,doctrine" and the user changes the tag to "c#,sql,doctrine" you have to know to delete the php tag as well.
So my code loops through existing tags to see which tags need to be removed, then I loop through the user supplied tags to see which need to be added.
An idea for update:
Store the value for user JS enabled/disabled in a hidden value
Tie an onchange event to the tags input then set a hidden variable to true so you know tags has changed
If JS enabled and tags has changed delete all tags belongs to this post then insert the actual tags (like first)
Fallback: if JS disabled you need to check submitted tags against saved ones.
For your first question, you can simplify things into a single query. The (non-parameterized) SQL would look something like this:
SELECT * FROM Tags WHERE name='foo' OR name='bar' OR name='etc'
/* and so on and so forth */
You can then cycle through in your PHP code to check which tags were returned; I'd use key_exists("keyname", $associativeArrayContainingQueryResults).
I'd do something similar for the second part of your query, too. I have no idea what the performance benefit is, though. SQL might cache the results from several smaller queries better, but I don't know if it would be faster overall.
I think there is a Taggable behaviour in Doctrine. Have a look at this, this can help.

[PHP]: Can someone help me fix this DataGrid class?

I am using following PHP class to display records. I also want to open another webpage when a row is selected according to a column value. This class is doing everything fine when this line is like:
$x->setQuery("*", "people");
If instead of *, I define columns like:
$x->setQuery("fname,lname,age", "people");
it stops identifying the clicked row id. Can someone help me out?
http://www.eyesis.ca/projects/datagrid.html
Please check the Example: 4 demo and source supplied there.
I'm not really familiar with this library, but I've had a peek at the source. I think you need to include the id column in the list of columns you pass to setQuery. You'd probably have the best results calling it like this:
$x->setQuery("id,fname,lname,age", "people", "id");
You could also try leaving it out of the first list, but still passing it as the third parameter which specifies the primary key.
The eyesis thing looks interesting. It is unfortunate they don't have API docs, say by running the code through phpdoc. The row selector piece, in the source code for example 4, just says
$x->addRowSelect("alert('You have selected id # %Id%')");
Shooting in the dark, I would try
$x->addRowSelect("alert('You have selected fname # %fname%')");
possibly capitalizing %Fname%.
If that didn't work, I'd reset that line with %Id%, and add id to the query
$x->setQuery("id,fname,lname,age", "people");
Again, docs would help me decide what the capitalization convention is.
How do you link two tables in the $x->setQuery, (example) I have $x->setQuery("*", "applicant inner join suritee on applicant.app_trn=suritee.app_trn","app_trn"); In this case applicant is the parent table with a primary key of app_trn and suritee is the child with a foreign key of app_trn

Categories