Can't get metadata selector text - javascript

This is a duplicate question to
node js puppeteer metadata
At the time of writing this question I don't have enough reputation to comment on the question.
I am writing some test scripts for a project and I want to test some seo metadata tags.
I check my selector in the chrome dev tools and it works fine.
document.querySelectorAll("head > meta[name='description']")[0].content;
and I receive the data no problem
but when I try to get it to work inside my testing script I can't seem to get a hold of the selector.
describe('guest jobs page', function () {
const {expect} = require('chai');
let page;
before(async function () {
page = await browser.newPage();
await page.goto('https://page');
});
after(async function () {
await page.close();
})
it('should have the correct page title', async function () {
expect(await page.title()).to.eql('page - Jobs');
});
it('should have the correct page description', async function () {
const DESCRIPTION_SELECTOR = "head > meta[name='description']";
await console.log( await page.evaluate((DESCRIPTION_SELECTOR) => document.querySelectorAll(DESCRIPTION_SELECTOR)));
expect(await page.$eval(DESCRIPTION_SELECTOR, element => element.textContent)).to.eql('page description content');
//this fails as no content is returned
//AssertionError: expected '' to deeply equal 'page description content'
});
});
any help would be appreciated, I don't know how to attach this question to the previous one without commenting so if someone could enlighten me about that I would also be very grateful. Thanks.

I believe console.log will be empty because DESCRIPTION_SELECTOR is undefined inside of page.evaluate.
In order to use a variable from the main script inside of page.evaluate one must explicitly pass it into the evaluating function:
await page.evaluate(DESCRIPTION_SELECTOR => document.querySelectorAll(DESCRIPTION_SELECTOR), DESCRIPTION_SELECTOR);
This is because page.evaluate operates in a kind of a sandbox and only has access to functions and variables declared at the web page opened by puppeteer (the so called "page context"). Since that page has no DESCRIPTION_SELECTOR, we must pass it in arguments of the page.evaluate, after the function to be evaluated. See also: documentation
As for page.$eval, it returns empty string because there is no textContent in meta tag, you need to use just content:
page.$eval(DESCRIPTION_SELECTOR, element => element.content)

Related

Is it possible to create custom commands in Playwright?

I'm looking for a way to write custom commands in Playwright like it's done in Cypress. Playwright Issues has one page related to it but I have never seen any code example.
I'm working on one test case where I'm trying to improve code reusability. Here's the code:
import { test, chromium } from '#playwright/test';
config();
let context;
let page;
test.beforeEach(async () => {
context = await chromium.launchPersistentContext(
'C:\\Users\\User\\AppData\\Local\\Microsoft\\Edge\\User Data\\Default',
{
headless: false,
executablePath: 'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe',
}
);
page = await context.newPage();
await page.goto('http://localhost:3000/');
});
test.afterEach(async () => {
await page.close();
await context.close();
});
test('Sample test', async () => {
await page.click('text=Open popup');
await page.click('_react=Button >> nth=0');
await page.click('text=Close popup');
});
I'm trying to create a function that will call hooks test.beforeEach() and test.afterEach() and the code inside them.
In the Playwright Issue page, it says that I need to move it to a separate Node module and then I would be able to use it but I'm struggling to understand how to do it.
The example you're giving can be solved by implementing a custom fixture.
Fixtures are #playwright/test's solution to customizing/extending the test framework. You can define your own objects (similar to browser, context, page) that you inject into your test, so the test has access to it. But they can also do things before and after each test such as setting up preconditions and tearing them down. You can also override existing fixtures.
For more information including examples have a look here:
https://playwright.dev/docs/test-fixtures

Is there an issue with having multiple eventListeners in one Javascript file?

So i have a JS file linked to my project. Inside that file i have three buttons with eventListeners listening for a "click" on each. The issue is that whichever button is placed first in the Javascript throws a "Cannot read property 'addEventListener' of null" at that position. I have checked everything spelling, assignment everyting but i still get the error.
When i split them up and place them in different JavaScript files there is no issue. What am i missing? am i making a noob mistake? Here's my code for reference:
const btnsignUp = document.querySelector('.btnSU')
const btnCancel = document.querySelector('.btnCancel')
const auth = firebase.auth()
btnsignUp.addEventListener('click', e => {
const promise = auth.createUserWithEmailAndPassword(username.value,
pwd1.value)
promise.catch(e => alert(e.message))
alert("Signed Up")
}
const btnLogin = document.querySelector('.btnLogin')
const btnLogCncl = document.querySelector('.btnLogCncl')
const auth = firebase.auth()
btnLogin.addEventListener('click', e => {
const promise = auth.signInWithEmailAndPassword(loginusrname.value,
loginpwd.value)
promise.catch(e=>alert(e.message))
alert("Signed In " + loginusrname.value)
window.open("/report.html")
})
The problem might be that the element hasn't loaded yet (this is just a possible answer since you haven't provided enough code to verify this).
You can solve this by putting your script tag at the bottom of your page, right before your </html>, or you could wrap the whole code in a function, and call it buy doing <body onload="myFunction()"> (look at this), or you can use Jquery and put it in the callback function: $(document).ready(() => {...});.

Puppeteer identifier string variable won't parse; Unsure why

I'm trying to have a string be used inside a puppeteer string, it won't work for some reason.
Specifically with this code
await page.waitForSelector('div[class = "sh-dlr__list-result"')
When i try to parse in a variable
let identified1 = 'div[class = "sh-dlr__list-result"'
so making
await page.waitForSelector(identified1)
It won't work. This is really limiting, is there a way around this issue?
This is the expanded code
https://jsfiddle.net/hewlbern/6p7kdozt/10/
Run it in your computer, jsfiddle unsure if I can run it from there.
I believe it is creating a cors error now - very weird! Why would using a variable create a cors error : /
Thanks!
The reason is because you're declaring identified inside the page.evaluate(). So, when you do the following it's already out of scope.
if (currentPage < pagesToScrape) {
console.log(identified1);
await Promise.all([
await page.click(buttonSelector),
await page.waitForSelector(identified),
]);
}
You did log the identified1 but you're using identified for the selector.
You'll have to pass the identifier2 to the pageFunction like so:
let newProducts = await page.evaluate(({ identifier2 }) => {
// ...
},{ identifier2 });
See here some examples:

I need close and open new browser in protractor

I have a simple test:
beforeEach(function () {
lib.startApp(constants.ENVIRONMENT, browser);//get url
loginPageLoc.loginAs(constants.ADMIN_LOGIN,constants.ADMIN_PASSWORD,
browser);// log in
browser.driver.sleep(5000); //wait
});
afterEach(function() {
browser.restart(); //or browser.close()
});
it('Test1' , async() => {
lib.waitUntilClickable(adminManagersPage.ButtonManagers, browser);
adminManagersPage.ButtonManagers.click();
expect(element(by.css('.common-popup')).isPresent()).toBe(false);
});
it('Test2' , async() => {
lib.waitUntilClickable(adminManagersPage.ButtonManagers, browser);
adminManagersPage.ButtonManagers.click();
expect(element(by.css('.common-popup')).isPresent()).toBe(false);
});
The first iteration looks fine, but after .restart() I get:
Failed: This driver instance does not have a valid session ID (did you
call WebDriver.quit()?) and may no longer be used. NoSuchSessionError:
This driver instance does not have a valid session ID (did you call
WebDriver.quit()?) and may no longer be used.
If I use .close() I get:
Failed: invalid session id
But if I change Test2 on simple console.log('case 1'); it looks fine.
Please explain what am I doing wrong?
You are declaring your functions as async but are not awaiting the any actions within. If you are not setting your SELENIUM_PROMISE_MANAGER to false in your config then you will see unexpected behavior throughout your test when declaring async functions. This async behavior is likely the cause of your issue so I would ensure SELENIUM_PROMISE_MANAGER:false and ensure your awaiting your actions in each function.
The reason your test passes if you change the second test to just be console.log() is because you are not interacting with the browser and therefore the selenium session ID is not required. Every time the browser is closed the selenium session id will be destroyed and a new one created when a new browser window is launched.
Also you should be aware that there is a config setting you can enable so you do not need to do it manually in your test.
Update: Adding code examples of what I have described:
Note: If you have a lot of code already developed it will take serious effort to convert your framework to Async/await syntax. For a quicker solution you could try removing the async keywords from your it blocks
Add these to your config
SELENIUM_PROMISE_MANAGER:false,
restartBrowserBetweenTests:true
and change you spec to
beforeEach(async function () {
await lib.startApp(constants.ENVIRONMENT, browser);//get url
await loginPageLoc.loginAs(constants.ADMIN_LOGIN, constants.ADMIN_PASSWORD,
browser);// log in
await browser.driver.sleep(5000); //wait
});
it('Test1', async () => {
await lib.waitUntilClickable(adminManagersPage.ButtonManagers, browser);
await adminManagersPage.ButtonManagers.click();
expect(await element(by.css('.common-popup')).isPresent()).toBe(false);
});
it('Test2', async () => {
await lib.waitUntilClickable(adminManagersPage.ButtonManagers, browser);
await adminManagersPage.ButtonManagers.click();
expect(await element(by.css('.common-popup')).isPresent()).toBe(false);
});
There is a relevant configuration option:
// If true, protractor will restart the browser between each test.
restartBrowserBetweenTests: true,
Add the above in your config to restart browser between your tests.
Hope it helps you.

TestCafe - How to check if a web element exists or does not exist without failing the test?

I'm trying to write a script that needs to adapt it's workflow behavior depending on whether a particular browser object found by CSS selector exists or does not exist.
I do not want to use a document.getElementByID method as this is not technically a CSS selector, and our entire enterprise is standardized on CSS selector so anything that walks the DOM other then a CSS selector won't make it past our code review process anyway.
var thing = await things.thingSelector(thingName);
if (await t.expect(thing.exists).notOk()) {
await t.click(things.OpenThing(thingName));
} else {
return false;
}
return true;
Where thingSelector is:
const thingSelector = name =>
Selector('p.thing-header-title span')
.withText(name)
.parent('div.thing');
Where OpenThing is:
const OpenThing = name =>
thingSelector(name)
.find('a.thing-footer-item')
.withText('Open');
I need to be able to continue execution if the object is not there and I'm checking that it exists, or if the object is there and I'm checking that it does not exist, and also the cases where the object is not there and it does not exist and the object is not there and I'm checking that it does not exist.
In all cases I still need to proceed with the workflow.
I've tried both sides of the logic coin:
if (!await t.expect(thing.exists).ok())
And
if (await t.expect(thing.exists).notOk())
If one of the above doesn't fail in one scenario it will fail in the other, and the other one will fail in the scenario that the first one didn't fail. I need something that will give me the logic, but not ever fail the script execution and still allow me to return either True or False depending on if the object is present or not present.
Thank you in advance for helping me to solve this problem, and also to learn and grow in my Javascript skills!
You can check the async exists property in the if condition in the following way:
if(await things.thingSelector(thingName).exists) {
// do something
}
You can use the following assertions to test existence and non-existence elements:
test('Test existence and non-existence elements', async t => {
await t
.expect(Selector('#existing-element').exists)
.expect(Selector('#non-existing-element').exists).notOk()
});
How to check if an element exists:
test('Element with id "element" exists', async t => {
await t.expect(Selector('#element').exists).ok(); });
How to check if an element does NOT exist:
test('Element with id "element" shouldn\'t exist', async t => {
await t.expect(Selector('#element').exists).notOk(); });
Check out the official documentation.
this is working for me, you can give it a try
async veriryCreativeIconButtonNotExists(){
await t.expect(this.exportButton.exists).ok()
await t.expect(this.columnPickerIcon.exists).ok()
await t.expect(this.filterColumnIcon.exists).ok()
if (await t.expect(this.columnPickerIcon.exists).ok()){
await t.expect(this.creavtiveIconButton.exists).ok()
await t.click(this.creavtiveIconButton)
await t.expect(this.creativeImage.exists).ok()
await t.click(this.creativeImage)
} else {
return false;
}
return true;

Categories

Resources