why JEST test fails due to closing browser by puppeteer - javascript

I am using JEST + Puppeteer to run functional tests on hosted web app.
here is test code:
const puppeteer = require('puppeteer');
const url = 'https://somewebsite.com';
const login = (async(page, login, password) =>{
await page.goto(url)
await page.waitForSelector('#mat-input-0')
await page.type('#mat-input-0', login)
await page.type('#mat-input-1', password)
await page.click('button')
})
beforeEach(async () => {
browser = await puppeteer.launch({ headless: false });
page = await browser.newPage();
});
afterEach(async () => {
await browser.close();
});
describe('login to website test', () => {
test('non existent user try', async() => {
jest.setTimeout(300000);
await login(page, 'user#email.com', 'upsiforgoTTThepassword')
await page.waitFor(1000)
var element = await page.$eval('.mat-simple-snackbar', (element) => {
return element.textContent.trim()
})
expect(element).toBe('User not Found')
})
})
And the problem I got is, that if I use puppeteer function await browser.close(); to exit browser after test ends It is automatically failed and I get the error in terminal:
● Test suite failed to run
Protocol error: Connection closed. Most likely the page has been closed.
and if I don't close browser after test ends it passes as it should.

I found out if I comment out preset in my jest.config.js, the error stops to occur:
// preset: "jest-puppeteer",

Related

jest puppeteer how to use setTimeout

I am a newbie at running Jest puppeteer.
I'm trying to run a test suite locally that I did not write.
All the tests fail to run and I get this error pointing at beforeEach...
"beforeEach(async () => {"
"thrown: "Exceeded timeout of 5000 ms for a hook.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test.""
Where / how exactly should I place the setTimeout?
Is there something else I am missing or have in the wrong spot?
const baseURL = "http://localhost:1234";
const puppeteer = require('puppeteer');
beforeEach(() => {
// Reset mock function's states before each test.
jest.clearAllMocks();
});
describe("chatbot", () => {
beforeEach(async () => {
const browser = await puppeteer.launch({headless: false, slowMo: 250,});
const page = await browser.newPage();
await page.goto(baseURL, { waitUntil: "load" });
// set the fade-ins to 0 ms to prevent timeouts in tests
await page.evaluate(() => { window.animationDelay = 0 })
await page.click("#chat-circle");
await browser.close()
});
it("should show contact info when the user enters 'contact'", async () => {
// submit the form with a message, expect to see the response
const message = "contact";
await page.evaluate(() => {
// get this same const in the page's context
const message = "contact";
$("#chat-input").val(message)
});
await page.click("#chat-submit");
await expect(page).toMatch("We have 24 hour phone support. Our phone number is +01 312 555 8432. We look forward to hearing from you!");
});
it("should show credit card help message when the user enters 'credit card'", async () => {
// submit the form with a message, expect to see the response
const message = "credit card";
await page.evaluate(() => {
// get this same const in the page's context
const message = "credit card";
$("#chat-input").val(message)
});
await page.click("#chat-submit");
await expect(page).toMatch("You can pay with any major credit card. Enter your card details and billing address at checkout.");
});
it("should show payment help message when the user enters 'payment'", async () => {
// submit the form with a message, expect to see the response
const message = "payment";
await page.evaluate(() => {
// get this same const in the page's context
const message = "payment";
$("#chat-input").val(message)
});
await page.click("#chat-submit");
await expect(page).toMatch("We have three payment options: credit card, paypal, or apple pay. Choose your preferred method at checkout.");
});
it("should show help options when the users enters 'help'", async () => {
// submit the form with a message, expect to see the response
const message = "help";
await page.evaluate(() => {
// get this same const in the page's context
const message = "help";
$("#chat-input").val(message)
});
await page.click("#chat-submit");
await expect(page).toMatch("Enter a keyword for help with a topic: contact, payment, credit card, destinations.");
});
});
Thank you
You just need to place it on the top
const baseURL = "http://localhost:1234";
const puppeteer = require('puppeteer');
jest.setTimeout(500000);
beforeEach(() => {
// Reset mock function's states before each test.
jest.clearAllMocks();
});
....

UnhandledPromiseRejectionWarning: Error: Evaluation failed theme is not defined

Before I start the question, I am new in JavaScript, and I have very basic knowledge of async js, but i need to solve this so i can have my first project functional.
I am trying to build a scraping app using Node and Puppeteer. Basically, the user enters a URL ("link" in the code below), puppeteer goes trough the website code, tries to find the specific piece and returns the data. That part I got working so far.
The problem is when a user enters a URL of a site that doesn't have that piece of code. In that case, I get UnhandledPromiseRejectionWarning: Error: Evaluation failed theme is not defined
What do I do so when there is an error like that, I can catch it and redirect the page instead of Getting Internal Server error.
app.post("/results", function(req, res) {
var link = req.body.link;
(async link => {
const browser = await puppeteer.launch({ args: ['--no-sandbox'] })
const page = await browser.newPage()
await page.goto(link, { waitUntil: 'networkidle2'})
const data = await page.evaluate('theme.name');
await browser.close()
return data
})(link)
.then(data => {
res.render("index", {data: data, siteUrl: link});
})
})
You can extend the async part to the whole route handler and do whatever you want on catch:
app.post('/results', async (req, res) => {
try {
const link = req.body.link
const browser = await puppeteer.launch({ args: ['--no-sandbox'] })
const page = await browser.newPage()
await page.goto(link, { waitUntil: 'networkidle2'})
const data = await page.evaluate('theme.name')
await browser.close()
res.render("index", {data: data, siteUrl: link})
} catch(e) {
// redirect or whatever
res.redirect('/')
}
});

MutationObserver is not working for Linkedin unread message count icon

I'm trying to build an automation for my Linkedin account so that whenever I get a message, I want to do something custom with it.
I'm using Puppeteer and MutationObserver inside page.evaluate call after loading my Linkedin profile with my li_at session cookie.
But it fails to fire an event even when I see the node changing the textContent.
const puppeteer = require('puppeteer');
(async function main() {
try {
const browser = await puppeteer.launch({ devtools: true, headless: false });
const page = await browser.newPage();
await page.setBypassCSP(true);
await page.setDefaultNavigationTimeout(0);
await page.setCookie({
'name': 'li_at',
'value': 'putYourSessionCookieHere',
'domain': '.www.linkedin.com'
})
await page.goto('https://www.linkedin.com', {waitUntil: 'networkidle2'});
await page.exposeFunction('puppeteerMutationListener', puppeteerMutationListener);
await page.evaluate(() => {
const target = document.querySelector('#messaging-nav-item .nav-item__badge-count');
const observer = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
window.puppeteerMutationListener(
mutation.removedNodes[0].textContent,
mutation.addedNodes[0].textContent,
);
}
});
observer.observe(
target,
{ childList: true},
);
});
} catch (err) {
console.error(err);
}
})();
function puppeteerMutationListener(oldValue, newValue) {
console.log(`${oldValue} -> ${newValue}`);
}
To reproduce the issue, you would need:
A Linkedin account
A helpful coworker with a linkedin account up for messaging you OR you can change the textContent of the Node by yourself
Any ideas on why this may be happening?

I can't go from a page to another using page.goto() - Puppeteer

I'm trying to make a InstagramBot that logs in and then go to some profile, my code worked yesterday for awhile and than it just stopped working .
I've tried to clone my repository from github, but it does'n work either, sometimes it works again, but if I try to create another function, the code just ignore the line of the code that changes the page.
I've also tried to create a new page and then in this new page use the goto function and it worked, but the account doesn keep logged in
The version of puppeteer that I'm using: 1.16.0
The version of node.js that I'm using: v10.15.3
const puppeteer = require('puppeteer');
const BASE_URL = "https://www.instagram.com/accounts/login/?hl=en&source=auth_switcher";
const instagram = {
browser: null,
page: null,
profile_url: null,
initialize: async (profile) => {
instagram.browser = await puppeteer.launch({
headless: false
})
instagram.profile_url = await "https://www.instagram.com/" + profile;
instagram.page = await instagram.browser.newPage();
await instagram.page.goto(BASE_URL, {waitUntil: 'networkidle2'});
},
login: async(username, password) =>{
await instagram.page.waitFor(1000);
await instagram.page.type('input[name="username"]', username);
await instagram.page.type('input[name="password"', password);
await instagram.page.click('button[type="submit"]');
await instagram.page.waitFor(1500);
await console.log(instagram.profile_url);
await instagram.page.goto(instagram.profile_url, {timeout: 0, waitUntil: 'domcontentloaded'}); // the code just ignore this line
await instagram.page.waitFor(1000);
},
getPhotosLinks: async() => {
console.log("Do something here");
}
}
module.exports = instagram;
It doesn't give any error message, just doesn't work
Replace
await instagram.page.click('button[type="submit"]');
await instagram.page.waitFor(1500);
with
await Promise.all([
instagram.page.click('button[type="submit"]');,
instagram.page.waitForNavigation()
]);
and see if it works

Puppeteer - unable to perform action on a selector when run on Jenkins

I am using Puppeteer to test the login page of my application.
The below code runs fine on my local system but when run on Jenkins 9 times out of 10, I get error (mentioned below).
I have tried different things to fix this but haven't been successful. Also added setTimeOut but even that doesn't help to fix this.
Here is the sample code:
const puppeteer = require('puppeteer');
const CREDS = require('../creds');
describe('Login & Title', () => {
var browser, page;
var url = 'https://www.example.com/login'
beforeEach (async () => {
browser = await puppeteer.launch({
args: ['--no-sandbox'], headless: true
});
page = await browser.newPage();
await page.goto(url);
})
afterEach (() => {
browser.close()
})
test('Test for Page Title', async () => {
var millisecondsToWait = 500;
setTimeout(function() {
}, millisecondsToWait);
const USERNAME_SELECTOR = '#inputUserName';
const PASSWORD_SELECTOR = '#inputPassword';
const BUTTON_SELECTOR = 'body > div > ng-view > form > div:nth-child(3) > button';
await page.click(USERNAME_SELECTOR);
await page.keyboard.type(CREDS.username);
await page.click(PASSWORD_SELECTOR);
await page.keyboard.type(CREDS.password);
await page.click(BUTTON_SELECTOR);
await page.waitForNavigation();
const title = await page.title();
expect(title).toBe("Example Website");
});
})
I am getting error:
console.assert node_modules/puppeteer/lib/FrameManager.js:597
AssertionError [ERR_ASSERTION]: No node found for selector: #inputUserName
FAIL __tests__/login.test.js
Login & Title
✕ Test for Page Title (513ms)
● Login & Title functionality.. › Test for Page Title
TypeError: Cannot read property 'click' of null
at Frame.click (node_modules/puppeteer/lib/FrameManager.js:598:18)
Any pointers or help would be great! Thanks in Advance.

Categories