I'm trying to run a playwright test that keeps failing the screenshot match because of timestamps (ex. 3 hours ago, 1 day ago, 5 days ago) that are posted on the page next to some content, not matching the current timestamps that have changed because the test is being run after the initial baseline screenshot is taken.
What is a way that I can store the current date and time at the time of capturing baseline screenshots and telling playwright this is always the timestamp I want to compare against in all tests?
As I see it, as long as you don't ignore the date comparison in your screenshots, they will keep throwing errors. Take into account your snapshot is just a moment in time, we may say. so if your baseline snapshot (the one you compare your current status against) contains the text "5 days ago", that's unchangeable unless you update the snapshot, but the whole comparing snapshots is all about comparing current state vs previous state to check there are no unwanted regressions, so updating the snapshot for this test every time would not make much sense.
In my opinion, you should ignore the given text. A good way to do it is using the option "mask" included in version 1.20. So imagine you want to ignore the number of stars the playwright repo has in its homepage. You could do this:
test('homepage', async({ page }) => {
await page.goto('https://playwright.dev/');
const stars = page.locator('.gh-count');
expect(await page.screenshot({ mask: [stars] })).toMatchSnapshot();
});
This would take a snapshot of playwright's homepage, masking the element with the stars count, sticking the element into a pink-coloured box. That would prevent the snapshots from failing, no matter how many stars the repo gets.
If for whatever reason you cannot update your version up to 1.20, you can also "fake" the element with the evaluate() function, from changing the text before you take the snapshot to a fixed text (with the innerHTML property) or even making the element itself disappear changing its visibility with the setAttribute property. It's all about getting creative on this regard.
I know the question is old, but maybe someone will find the answer useful. What we did to go around the issue is inject css to hide the time stamps:
await page.addStyleTag({
content: `
.timestamp { display: none !important; }
`})
You just need to find the selector for the timestamp and use this code to hide it.
Related
I would like to store the text from an object locator and use it for assertion. For instance, I have a trade number - 1234. This trade number only appears after a transaction, so it is not static on other screens. This number is located on several other screens and I need to validate that it appears. I am able to locate the element through inspect and Playwright accepts it, but having issues:
Grabbing the text (1234)
Then setting up an assertion statement to compare it
Below are my humble and naïve attempts:
async getConfirmNumber() {
//Store the contents in the page locator which has the trade number
const tradeNumber = page.locator('div:nth-of-type(2) > .col-md-9.display-value.ng-binding').textContent;
//Navigate to a different screen which now will display the trade number
await this.page.click('a[caption="History"]')
await this.page.click('a[href="#/trade-summary"]')
//Line of code that I am not sure how to correctly write. ".bidconfirmation" is the locator on the new screen which displays the trade number.
//If the contents or value of ".bidconfirmation" is NOT 1234 then an error needs to display.
await expect(tradeNumber).toHaveCSS('.bidconfirmation', tradeNumber);
}
Just to let you know I would change the tag on this post to playwright-JavaScript to better reach the intended audience.
However, if I understand your question correctly you are trying to get the text content of an element but the textContent() method is not working, I would try to use the innerText() method and see if that works.
Apologies if this is a little off as I work with the java version of Playwright but you could do:
const tradeNumber = page.locator('div:nth-of-type(2) > .col-md-9.display-value.ng-binding').innerText(); //BTW I would change this locator to something unique or a little more stable -- this should give you the tradeNumber
//then I'm not 100% sure what your trying to do here but if I understand correctly this might help
await expect(page.locator('.bidconfirmation').toHaveValue(tradeNumber));
I hope this helped a little, Im sorry I couldn't really get an understanding fully of the question you were asking but feel free to take a look at playwright.dev to find documentation surrounding Playwright.
I have several similar pages that all load up several header elements based on various inputs. They are auto-generated.
I am writing a test cafe test to confirm that the correct headers have loaded in the correct order for each page. Some pages have more headers, some pages have fewer headers.
My tests all follow the same basic pattern:
test.disablePageCaching('log in and check that columns load in correct order',
async(tc: TestController)=>{
const myPage = new MyPage(tc)
await tc.expect(myPage.getScreen().exists).ok() // Confirm page load
myPage.nagivateToRelevantPage();
const headers = Selector(headerClassName)
const expectedHeaders = ['array','of','expected','values']
const count = await headers.count
for (let i =0; i<count;i++){
const text = await headers.nth(i).innerText.toLowerCase()
await tc.expect(expectedHeaders[i].toLowerCase()).eql(text)
}
(if you spot any small syntax errors, please rest assured that it isn't a matter of an errant parenthesis or a misspelled variable name)
I have 4 of these tests in the same file, and I hop from one to the next. The thing is, I seem to be retaining old data when I hop from one text to the next.
Say my first test checked 10 header elements; my headers.count value is 10. If my second test only contains 3 header elements, I would expect my headers.count value to be 3. Instead, my headers.count value is still 10. Test Cafe seems to just be overwriting the previous data, while retaining the data from the previous test.
Is there an option of some sort to tell Test Cafe to purge this old data in between tests? I have tried the disablePageCaching option, but that is not working for me.
I eventually figured this out; the issue was that I was collecting data too soon after navigating to a new page. I needed to call await tc.expect(myPage.getScreen().exists).ok() after navigating to the new page; that gave test cafe enough time to recognize which data was new and which data was old.
I'm trying to input a date string formatted mm/dd/yyyy into a Kendo React DatePicker control using nightwatch setValue. It seems that no matter what approach I take to select the control it always sets the cursor on the year portion first and typing then only fills in those four characters.
(For example if I provide '05/06/2016', all I see typed into the input is 'mm/dd/0016' and month and day never update.)
The control seems to work fine in a normal scenario if I click with the mouse on the month field, the cursor will display there and if I type 2 characters, a / 2 more characters another / and then the last 4 the control is working properly. It just seems to be an issue with selenium selecting the control and DatePickers default behavior.
I've tried using browser.Key.LEFT_ARROW to see if I could move the cursor left twice first since the accessibility handling allows for it. I also tried calling clearValue() on the input first then typing from scratch but no success on either case.
I would rather not have select the date using the calendar control if I can avoid it.
Here's what my code looks like currently:
const consumerInfo = {
birthMonth: "05",
birthDay: "06",
birthYear: "2016",
birthDate: "05/06/2016",
};
const datePickerSelector = '.myDatePicker';
const datePickerInputSelector = '.myDatePicker .k-input';
browser.waitForElementVisible(datePickerSelector, DEFAULT_WAIT_TIME)
.waitForElementVisible(datePickerInputSelector, DEFAULT_WAIT_TIME)
.setValue('.myDatePicker .k-input, [
consumerInfo.birthYear,
browser.Keys.LEFT_ARROW,
consumerInfo.birthDay,
browser.Keys.LEFT_ARROW,
consumerInfo.birthMonth,
])
.assert.value(
datePickerInputSelector,
consumerInfo.birthDate,
`Birthdate is set to ${consumerInfo.birthDate}`
);
Any suggestions are appreciated.
While not perfect I came up with a solution so hopefully it helps some others should this come up.
The approach ended up being roughly similar to what I proposed above but allowing more time between each operation. I added it into a util function that accepts the selector to target the input control with along with the month/day/year to fill in the control with. It's possible the time intervals can be reduced in places to less than 500ms but without more exhausted testing that was better than 1000ms (which worked) and 100ms (which inconsistently worked).
See below:
const toDatePickerInsertion = (browser, pickerInputSelector) => ({
month,
day,
year,
}) => {
return browser
.click(pickerInputSelector)
.pause(500)
.keys(browser.Keys.LEFT_ARROW)
.pause(500)
.keys(browser.Keys.LEFT_ARROW)
.pause(500)
.keys(month)
.pause(500)
.keys(browser.Keys.RIGHT_ARROW)
.pause(500)
.keys(day)
.pause(500)
.keys(browser.Keys.RIGHT_ARROW)
.pause(500)
.keys(year);
};
I'm automating e2e tests with Protractor on an angular app.
However, I have an issue when sending keys on input fields.
The sendKeys would miss few characters everytime so I found a workaround :
static sendKeys(value, element){
value.split('').forEach((c) => element.sendKeys(c));
}
This works well but it takes more than 3 times the time the original sendKeys function would.
Well no problem my tests are still functionnal right ?
My app now has new fields with scripts behind them.
One of them is a datepicker input, you can either choose from the datePicker or type it manually. However, for today's date you would type 09022018 and the slashes are automatically appended at the right place (like so 09/02/2018). If you were to enter a wrong date the field is cleared.
Now back to the problem : it seems that both my implementation of sendKeys and the original one loose focus after each submitted key. This means that I can't enter a valid date in the input field as it's cleared after each simulated keypress.
I could use browser.executeScript to fix it but I wouldn't be able to test the functionnality adding slashes. Also, as you type, the datepicker is still open and refreshes after each keypress, you can select a date from it at any time and that is also a feature I want to test.
Thanks in advance
Use executeScript to set the date in backgrond, then use sendKeys to enter a space or Tab at the end to trigger the Keyborad event which will check the input and format the input with slash
function enterDate(date) {
var script = 'arguments[0].value=arguments[1]';
// input box for date
var dateBox = element(by.xxx(yyy));
browser.executeScript(script, dateBox, date);
dateBox.sendKeys(" ");
// or try send Tab
dateBox.sendKeys(protractor.Key.TAB);
}
enterDate('09022018');
You can try this solution on other fields you fixed but take 3 more time.
I'm running approx 30 scripted test cases (each test case is a script) in series and there are often failures that include: cannot identify specified element, element not present.
I've already added a lot of different methods to wait for an element to show up. Sometimes when it is clearly there, I guess Selenium has a hard time trying to find the element's id ?
I've included several
do{
if(selenium.isElementPresent("id=resultTable_0_0"){
selenium.click("viewResultForm:refresh_button");
}
}while (!selenium.isElementPresent("id=resultTable_0_0"));
and
if(selenium.isElementPresent("id=resultTable_0_0"))
selenium.isVisible("id=resultTable_0_0");
and
if(selenium.isElementPresent("id=resultTable_0_0_1_to"))
selenium.click("resultTable_0_0_1_to");
always checking if an element is even present before doing something. This probably has a huge impact on performance, but for now I just want my scripts to run error-free, completely robust. I have this piece of code:
do{
if(selenium.isElementPresent("id=resultTable_0_0")){
selenium.click("viewResultForm:refresh_button");
}
}while (!selenium.isElementPresent("id=resultTable_0_0"));
if(selenium.isElementPresent("id=resultTable_0_0"))
selenium.isVisible("id=resultTable_0_0");
if(selenium.isElementPresent("id=viewResultForm:currentDetailViewType"))
selenium.isVisible("id=viewResultForm:currentDetailViewType");
if(selenium.isElementPresent("id=viewResultForm:currentSearchDateType"))
selenium.isVisible("id=viewResultForm:currentSearchDateType");
if(selenium.isElementPresent("id=viewResultForm:currentLegalEntity"))
selenium.isVisible("id=viewResultForm:currentLegalEntity");
if(selenium.isElementPresent("id=viewResultForm:currentRollupBy"))
selenium.isVisible("id=viewResultForm:currentRollupBy");
if(selenium.isElementPresent("id=viewResultForm:currentSecurityAltId"))
selenium.isVisible("id=viewResultForm:currentSecurityAltId");
if(selenium.isElementPresent("id=viewResultForm:currentSecurityAltIdType"))
selenium.isVisible("id=viewResultForm:currentSecurityAltIdType");
if(selenium.isElementPresent("id=viewResultForm:currentDepoViewType"))
selenium.isVisible("id=viewResultForm:currentDepoViewType");
if(selenium.isElementPresent("id=viewResultForm:currentBusinessDate"))
selenium.isVisible("id=viewResultForm:currentBusinessDate");
System.out.println("Success T13001");
selenium.stop();
Even this will error out !!! and it wont fall through to reach selenium.stop and 'fake' a success. What can I do to build on the robustness of my scripts? Any help would be appreciated.
I'm using Selenium 2.20.0 on IE 8.
As per your question if its the problem of not finding the id of locators then try using other locators like css and xpath.
Apply selenium.waitforpagetoload when ever you move to a new page or you open a url.
If you are working on an ajax based application then selenium.waitforcondition would be gud to you.
Whereever you think that a locator may take some time to appear after some operation,Use proper waits for those elements.