selenium test is failing using selenium javascript webdriver - javascript

I have installed javascript selenium webdriver and write a first test like this
I am writing a test for login. I enter correct username and password and try to login.
describe('Checkout Google.com', function () {
let driver;
before(async function () {
// driver = await new Builder().forBrowser('chrome').build();
});
it('Search on Google', async function () {
let driver = await new Builder().forBrowser('chrome').build();
await driver.get('http://alpdev.s3-website-us-east-1.amazonaws.com/');
// await driver.findElement(By.name('q')).sendKeys('selenium', Key.RETURN);
this.timeout(5000);
await driver.findElement(By.xpath("//input[#placeholder='Email']")).sendKeys('owais#demoshop.com');
await driver.findElement(By.xpath("//input[#placeholder='Password']")).sendKeys('test');
await driver.findElement(By.className('btn-submit')).click().then(()=> done());
// assert.equal(title, 'dalenguyen - Google Search');
});
// close the browser after running tests
after(() => driver && driver.quit());
})
And my package json is like this
{
"name": "selenium-01",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha --recursive index.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"mocha": "^7.2.0",
"selenium-webdriver": "^4.0.0-alpha.7"
}
}
Now when i run ng run test so browser opens and test is passed visually meaning that login is happening but on console it prints like this
What's wrong here that it's giving an error.

So, I could not fully reproduce your case as the url in the script is not available anymore but found a few flaws though and tried some fixes.
First is your driver was declared twice.
Second, I believe the main problem (the reason you are getting the error mentioned above) is that you're using the then & done promises which are not needed as you're using the async & await functions.
Also I would recommend you use the css locators instead of the xpaths.
Another thing is you could use the async in the after(); closure, and you could use the arrow functions (async () => {}); all around instead of using the function keyword.
Below is your example but with a few changes and I am quite positive it will work (though if this is all on the google search page, there are no inputs on that page so those steps will fail, you'll have to add some extra steps to load the login page with the input fields available):
describe('Checkout Google.com', function () {
let driver;
before(async () => {
driver = await new Builder().forBrowser('chrome').build();
});
it('Search on Google', async () => {
await driver.get('http://alpdev.s3-website-us-east-1.amazonaws.com/');
await driver.findElement(By.name('q')).sendKeys('selenium', Key.RETURN);
await driver.sleep(5000);
// the steps below will fail as per the description above
await driver.findElement(By.css("input[placeholder='Email']")).sendKeys('owais#demoshop.com');
await driver.findElement(By.css("input[placeholder='Password']")).sendKeys('test');
await driver.findElement(By.className('btn-submit')).click();
// assert.equal(title, 'dalenguyen - Google Search');
});
// close the browser after running tests
after(async () => {
await driver.quit();
});
});
I hope this helps, please let me know.

Related

Puppeteer Web Scraper runs on local machine only but fails to deploy as Google Cloud Function

I have built a simple scraper with Puppeteer which I can run locally on my machine, but when I deploy it as a Google Cloud function, it's not working. The only error message I get from the Google Cloud Logs is:
Function failed on loading user code. This is likely due to a bug in
the user code.
Here are the steps I follow to deploy it the function; code is further below.
(Note: I'm outlining the process of zipping the files; I have tried the Cloud Function inline editor as well but am receiving the same error.)
Run npm install
Run zip -r my-app.zip *
Create new Google Cloud function
-- Name 'newFunction'
-- Memory: 1gb
-- Runtime: Node.js 14
-- Entry point: scrapeFunction
Upload Zip
index.js
const puppeteer = require('puppeteer');
const { BigQuery } = require('#google-cloud/bigquery');
async function scrapeFunction() {
const browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] });
const page = await browser.newPage();
await page.goto('<URL>', {waitUntil: 'load', timeout: 0});
await page.waitForSelector('span.text');
const info = await page.evaluate(() => {
return document.querySelector('span.text').innerText;
});
console.log(info);
// Write results to BigQuery table
const bigqueryClient = new BigQuery();
const dataset = bigqueryClient.dataset('xxx');
const table = dataset.table('yyy');
const rows = [{ info: info }];
await table.insert(rows);
await browser.close();
}
scrapeFunction();
package.json
{
"name": "newFunction",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"#google-cloud/bigquery": "^6.1.0",
"puppeteer": "^19.7.1"
}
}

Jest and Playwright: Go to youtube.com and search a video

for my job, I have been assigned to automate tests for a webapp that we developed. I have to write the automation scripts with Playwright and jest. In order to practice using Playwright, I have decided to make a script that looks up "Israel Adesanya" on the search bar in YouTube. My JavaScript is a bit inexperienced, but in order to work on this, I used yarn add playwright and yarn add jest directory structure looks like the following:
node_modules/
package.json
__tests__/
yarn-error.log
yarn.lock
my package.json:
{
"dependencies": {
"jest": "^26.5.3",
"playwright": "^1.5.1"
},
"scripts": {
"test": "jest"
}
}
in my __tests__ directory, I have a file titled playwright_test.js with the following code:
const { chromium } = require('playwright');
let browser;
let page;
beforeAll(async () => {
browser = await chromium.launch({headless: false});
});
afterAll(async () => {
await browser.close();
});
beforeEach(async () => {
page = await browser.newPage();
});
afterEach(async () => {
await page.close();
});
it('should work', async () => {
//expect(await page.title()).toBe('YouTube');
await page.fill('#search', 'Israel Adesanya')
await page.click('button#search-icon-legacy')
}, 30000);
When I do yarn test, this code only brings me to the YouTube page, but does nothing else before returning this error:
I was wondering what I do in order to be able to properly search a video on YouTube. For a bonus, after searching "Israel Adesanya" on YouTube, how do I make the script click the first video on YouTube?
This much I could tell you...
window.location.href = document.querySelector("#thumbnail").href;
will click navigate to the first Youtube video's href in the (a attribute).
The problem is that there is an SVG icon with the ID search
You should be able to get to the input with the selector #search-input input:
I found out how to do it. In my playwright_test.js file is now the following:
const { chromium } = require('playwright');
let browser;
let page;
beforeAll(async () => {
browser = await chromium.launch({headless: false});
});
afterAll(async () => {
await browser.close();
});
beforeEach(async () => {
page = await browser.newPage();
});
afterEach(async () => {
await page.close();
});
it('should work', async () => {
await page.goto('https://www.youtube.com');
//expect(await page.title()).toBe('YouTube');
await page.type('input#search', 'Israel Adesanya')
await page.click('button#search-icon-legacy')
await page.click('a#video-title')
await page.waitForSelector('#search', { state: 'attached' });
await page.waitForLoadState("networkidle")
}, 30000);

Import a file after the Jest environment has been torn down

I'm making a simple API with Express and I'm trying to add tests with Jest but when I try to run the tests it displays the next error:
ReferenceError: You are trying to `import` a file after the Jest environment has been torn down.
at BufferList.Readable (node_modules/readable-stream/lib/_stream_readable.js:179:22)
at BufferList.Duplex (node_modules/readable-stream/lib/_stream_duplex.js:67:12)
at new BufferList (node_modules/bl/bl.js:33:16)
at new MessageStream (node_modules/mongodb/lib/cmap/message_stream.js:35:21)
at new Connection (node_modules/mongodb/lib/cmap/connection.js:52:28)
/home/jonathangomz/Documents/Node/Express/Devotionals/node_modules/readable-stream/lib/_stream_readable.js:111
var isDuplex = stream instanceof Duplex;
^
TypeError: Right-hand side of 'instanceof' is not callable
I'm not sure to trust the result if right after jest break (or something like that):
My test is:
const app = require("../app");
const request = require("supertest");
describe("Testing root router", () => {
test("Should test that true === true", async () => {
jest.useFakeTimers();
const response = await request(app).get("/");
expect(response.status).toBe(200);
});
});
My jest configuration on package.json:
"jest": {
"testEnvironment": "node",
"coveragePathIgnorePatterns": [
"/node_modules/"
]
}
Notes:
I read about jest.useFakeTimers() but It's not working and I'm not sure if I'm using in the wrong way. I also tried adding it to the beforeEach method but nothing.
In my case, I had to add the package to transformIgnorePatterns in the jest config.
Add jest.useFakeTimers('modern') before the asynchronous call. Add jest.runAllTimers() after the asynchronous call. This will fast-forward timers for you.
const app = require("../app")
const request = require("supertest")
describe("Testing root router", () => {
test("Should test that true === true", async () => {
//Before asynchronous call
jest.useFakeTimers("modern")
const response = await request(app).get("/")
//After asynchronous call
jest.runAllTimers()
expect(response.status).toBe(200)
})
})
Try adding --testTimeout=10000 flag when calling jest, it works for me.
Information based on Testing NodeJs/Express API with Jest and Supertest
--testTimeout flag - This increases the default timeout of Jest which is 5000ms. This is important since the test runner needs to refresh the database before running the test
By adding jest.useFakeTimers() just after all your import.
What about making your test async ?
const app = require("../app");
const request = require("supertest");
describe("Testing root router",async () => {
test("Should test that true === true", async () => {
jest.useFakeTimers();
const response = await request(app).get("/");
expect(response.status).toBe(200);
});
});

protractor: random test fail

So I just started work on protractor tests and I'm facing the following problem - my tests fail inconsistently. Sometimes the test may pass and the next time it fails. Reasons to fail is very different, it may because it failed to find an element on a page or element does not have text in it (even if it has).
I'm running on Ubuntu 14.04, the same problem relevant for Chrome Version 71.0.3578.80 and Firefox Version 60.0.2. AngularJS Version 1.7.2 and Protractor Version 5.4.0. I believe the problem is somewhere in my code, so here below I provided an example of an existing code base.
Here is my protractor config
exports.config = {
rootElement: '[ng-app="myapp"]',
framework: 'jasmine',
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['./e2e/**/*protractor.js'],
SELENIUM_PROMISE_MANAGER: false,
baseUrl: 'https://localhost/',
allScriptsTimeout: 20000,
jasmineNodeOpts: {
defaultTimeoutInterval: 100000,
},
capabilities: {
browserName: 'firefox',
marionette: true,
acceptInsecureCerts: true,
'moz:firefoxOptions': {
args: ['--headless'],
},
},
}
And here capabilities for chrome browser
capabilities: {
browserName: 'chrome',
chromeOptions: {
args: [ "--headless", "--disable-gpu", "--window-size=1920,1080" ]
}
},
And finally, my test kit that failed a few times
const InsurerViewDriver = require('./insurer-view.driver');
const InsurerRefundDriver = require('./insurer-refund.driver');
const { PageDriver } = require('#utils/page');
const { NotificationsDriver } = require('#utils/service');
const moment = require('moment');
describe(InsurerViewDriver.pageUrl, () => {
beforeAll(async () => {
await InsurerViewDriver.goToPage();
});
it('- should test "Delete" button', async () => {
await InsurerViewDriver.clickDelete();
await NotificationsDriver.toBeShown('success');
await PageDriver.userToBeNavigated('#/setup/insurers');
await InsurerViewDriver.goToPage();
});
describe('Should test Refunds section', () => {
it('- should test refund list content', async () => {
expect(await InsurerRefundDriver.getTitle()).toEqual('REFUNDS');
const refunds = InsurerRefundDriver.getRefunds();
expect(await refunds.count()).toBe(1);
const firstRow = refunds.get(0);
expect(await firstRow.element(by.binding('item.name')).getText()).toEqual('Direct');
expect(await firstRow.element(by.binding('item.amount')).getText()).toEqual('$ 50.00');
expect(await firstRow.element(by.binding('item.number')).getText()).toEqual('');
expect(await firstRow.element(by.binding('item.date')).getText()).toEqual(moment().format('MMMM DD YYYY'));
});
it('- should test add refund action', async () => {
await InsurerRefundDriver.openNewRefundForm();
const NewRefundFormDriver = InsurerRefundDriver.getNewRefundForm();
await NewRefundFormDriver.setPayment(`#555555, ${moment().format('MMMM DD YYYY')} (amount: $2,000, rest: $1,500)`);
await NewRefundFormDriver.setPaymentMethod('Credit Card');
expect(await NewRefundFormDriver.getAmount()).toEqual('0');
await NewRefundFormDriver.setAmount(200.05);
await NewRefundFormDriver.setAuthorization('qwerty');
await NewRefundFormDriver.submit();
await NotificationsDriver.toBeShown('success');
const interactions = InsurerRefundDriver.getRefunds();
expect(await interactions.count()).toBe(2);
expect(await InsurerViewDriver.getInsurerTitleValue('Balance:')).toEqual('Balance: $ 2,200.05');
expect(await InsurerViewDriver.getInsurerTitleValue('Wallet:')).toEqual('Wallet: $ 4,799.95');
});
});
});
And here some functions from driver's, that I'm referencing in the test above
// PageDriver.userToBeNavigated
this.userToBeNavigated = async function(url) {
return await browser.wait(
protractor.ExpectedConditions.urlContains(url),
5000,
`Expectation failed - user to be navigated to "${url}"`
);
};
this.pageUrl = '#/insurer/33';
// InsurerViewDriver.goToPage
this.goToPage = async () => {
await browser.get(this.pageUrl);
};
// InsurerViewDriver.clickDelete()
this.clickDelete = async () => {
await $('[ng-click="$ctrl.removeInsurer()"]').click();
await DialogDriver.toBeShown('Are you sure you want to remove this entry?');
await DialogDriver.confirm();
};
// NotificationsDriver.toBeShown
this.toBeShown = async (type, text) => {
const awaitSeconds = 6;
return await browser.wait(
protractor.ExpectedConditions.presenceOf(
text ? element(by.cssContainingText('.toast-message', text)) : $(`.toast-${type}`)
),
awaitSeconds * 1000,
`${type} notification should be shown within ${awaitSeconds} sec`
);
}
// InsurerRefundDriver.getRefunds()
this.getRefunds = () => $('list-refunds-component').all(by.repeater('item in $data'));
// InsurerViewDriver.getInsurerTitleValue
this.getInsurerTitleValue = async (text) => {
return await element(by.cssContainingText('header-content p', text)).getText();
};
I can't upload the whole code here to give you better understanding because I have a lot of code till this moment, but the code provided above is the exact sample of approach I'm using everywhere, does anyone see a problem in my code? Thanks.
First of all add this block before exporting your config
process.on("unhandledRejection", ({message}) => {
console.log("\x1b[36m%s\x1b[0m", `Unhandled rejection: ${message}`);
});
this essentially colorfully logs to the console if you missed async/await anywhere, and it'll give confidence that you didn't miss anything.
Second, I would install "protractor-console" plugin, to make sure there is no errors/rejections in the browser console (i.e. exclude possibility of issues from your app side) and add to your config
plugins: [{
package: "protractor-console",
logLevels: [ "severe" ]
}]
Then the next problem that I would expect with these signs is incorrect waiting functions. Ideally you have to test them separately as you develop your e2e project, but since it's all written already I'll tell you how I debugged them. Note, this approach won't probably help you if your actions are less than a sec (i.e. you can't notice them). Otherwise follow this chain.
1) I created run configuration in WebStorm, as described in my comment here (find mine) How to debug angular protractor tests in WebStorm
2) Set a breakpoint in the first line of the test I want to debug
3) Then execute your test line by line, using the created run config.
When you start debugging process, webstorm opens up a panel with three sections: frames, console, variables. When the variables section has a message connected to localhost and no variables listed, this means your step is still being executed. Once loading completed you can see all your variables and you can execute next command. So the main principle here is you click Step Over button and watch for variables section. IF VARIABLES APPEAR BEFORE THE APPS LOADING COMPLETED (the waiting method executed, but the app is still loading, which is wrong) then you need to work on this method. By going this way I identified a lot of gaps in my custom waiting methods.
And finally if this doesn't work, please attach stack trace of your errors and ping me
I'm concerned about this code snippet
describe(InsurerViewDriver.pageUrl, () => {
beforeAll(async () => {
await InsurerViewDriver.goToPage();
});
it('- should test "Delete" button', async () => {
await InsurerViewDriver.clickDelete();
await NotificationsDriver.toBeShown('success');
await PageDriver.userToBeNavigated('#/setup/insurers');
await InsurerViewDriver.goToPage(); // WHY IS THIS HERE?
});
describe('Should test Refunds section', () => {
it('- should test refund list content', async () => {
// DOESN'T THIS NEED SOME SETUP?
expect(await InsurerRefundDriver.getTitle()).toEqual('REFUNDS');
// <truncated>
You should not depend on the first it clause to set up the suite below it. You didn't post the code for InsurerRefundDriver.getTitle() but if that code does not send the browser to the correct URL and then wait for the page to finish loading, it is a problem. You should probably have await InsurerViewDriver.goToPage(); in a beforeEach clause.
After some time research I found what was the problem. The cause was the way I'm navigate through the app.
this.goToPage = async () => {
await browser.get(this.pageUrl);
};
Turns out, that browser.get method is being resolved when url changed, but now when angularjs done compile. I used the same approach in every test kit, that's why my tests were failing inconsistently, sometimes page was not fully loaded before test start.
So here is an approach that did the trick
this.goToPage = async () => {
await browser.get(this.pageUrl);
await browser.wait(EC.presenceOf(`some important element`), 5000, 'Element did not appear after route change');
};
You should ensure that page done all the compiling job before moving on.
It seems this could be due to asynchronous javascript.
browser.ignoreSynchronization = true; has a global effect for all your tests. you may have to set it back to false, so protractor waits for angular to be finished rendering the page. e.g. in or before your second beforeEach function

Sinon spy.called no working

Background
I have a small server that receives data from a machine. Every time I receive a message I call a function in a dispatcher object that simply console.logs everything it receives.
Problem
The code works well as I can see the console.logs in the console, but Sinon spy.called doesn't work. It is always false no matter how many times I call dispatcher.onMessage.
Code
server.js
const eventDispatcher = {
onMessage: console.log,
};
const server = (dispatcher = eventDispatcher) => {
//this gets called everytime the server receives a message
const onData = data => {
//Process data
//....
dispatcher.onMessage(data);
};
const getDispatcher = () => dispatcher;
return Object.freeze({
getDispatcher
});
};
test.js
describe("message sender", () => {
const myServer = serverFactory();
it("should send information to server", () => {
dummyMachine.socket.write("Hello World!\r\n");
const dataSpy = sinon.spy(myServer.getDispatcher(), "onMessage");
expect(dataSpy.called).to.be.true; //always fails!
});
});
Research
After reading similar posts I believe this happens due to some layer of indirection, as pointed in:
Sinon Spy is not called if the spied method is called indirectly
And should be fixed via using this:
Sinon.spy on a method is not invoked
However, looking at my code I really can't get what I am missing.
Question
What am I doing wrong?
MCVE
Directory Structure
Project_Folder
|____package.json
|____server.js
|____test
|____ dummyMachine_spec.js
package.json
{
"name": "sinon-question",
"version": "1.0.0",
"description": "MCVE about a dummy machine connecting to a server for StackOverflow",
"main": "server.js",
"scripts": {
"test": "NODE_ENV=test mocha --reporter spec --slow 5000 --timeout 5000 test/*_spec.js || true"
},
"author": "Pedro Miguel P. S. Martins",
"license": "ISC",
"devDependencies": {
"chai": "^3.5.0",
"mocha": "^3.3.0",
"sinon": "^2.2.0"
},
"dependencies": {
"net": "^1.0.2"
}
}
server.js
"use strict";
const net = require("net");
const eventDispatcher = {
onMessage: console.log,
};
const server = (dispatcher = eventDispatcher) => {
let serverSocket;
const onData = data => {
//Process data
dispatcher.onMessage(`I am server and I got ${data}`);
};
const start = (connectOpts) => {
return new Promise(fulfil => {
serverSocket = net.createConnection(connectOpts, () => {
serverSocket.on("data", onData);
fulfil();
});
});
};
const stop = () => serverSocket.destroy();
const getDispatcher = () => dispatcher;
return Object.freeze({
start,
stop,
getDispatcher
});
};
module.exports = server;
test/dummyMachine.js
"use strict";
const chai = require("chai"),
expect = chai.expect;
const sinon = require("sinon");
const net = require("net");
const serverFactory = require("../server.js");
describe("Dummy Machine", () => {
const dummyMachine = {
IP: "localhost",
port: 4002,
server: undefined,
socket: undefined
};
const server = serverFactory();
before("Sets up dummyReader and server", done => {
dummyMachine.server = net.createServer(undefined, socket => {
dummyMachine.socket = socket;
});
dummyMachine.server.listen(
dummyMachine.port,
dummyMachine.IP,
undefined,
() => {
server.start({
host: "localhost",
port: 4002
})
.then(done);
}
);
});
after("Kills dummyReader and server", () => {
server.stop();
dummyMachine.server.close();
});
it("should connect to server", done => {
dummyMachine.server.getConnections((err, count) => {
expect(err).to.be.null;
expect(count).to.eql(1);
done();
});
});
it("should send information to server", () => {
dummyMachine.socket.write("Hello World\r\n");
const dataSpy = sinon.spy(server.getDispatcher(), "onMessage");
expect(dataSpy.called).to.be.true; //WORK DAAMN YOU!
});
});
Instructions for MCVE
Download the files and create the directory structure indicated.
Enter project folder and type npm install on a terminal
Type npm test
The first test should pass, meaning a connection is in fact being made.
The second test will fail, even though you get the console log, proving that onMessage was called.
The main problem is that it's not enough to just spy on onMessage, because your test will never find out when it got called exactly (because stream events are asynchronously delivered).
You can use a hack using setTimeout(), and check and see if it got called some time after sending a message to the server, but that's not ideal.
Instead, you can replace onMessage with a function that will get called instead, and from that function, you can test and see if it got called with the correct arguments, etc.
Sinon provides stubs which can be used for this:
it("should send information to server", done => {
const stub = sinon.stub(server.getDispatcher(), 'onMessage').callsFake(data => {
stub.restore();
expect(data).to.equal('I am server and I got Hello World\r\n');
done();
});
dummyMachine.socket.write("Hello World\r\n");
});
Instead of the original onMessage, it will call the "fake function" that you provide. There, the stub is restored (which means that onMessage is restored to its original), and you can check and see if it got called with the correct argument.
Because the test is asynchronous, it's using done.
There are a few things to consider:
You can't easily detect if, because of a programming error, onMessage doesn't get called at all. When that happens, after a few seconds, Mocha will timeout your test, causing it to fail.
If that happens, the stub won't be restored to its original and any subsequent tests that try to stub onMessage will fail because the method is already stubbed (usually, you work around this by creating the stub in an onBeforeEach and restore it in an onAfterEach)
This solution won't test the inner workings of onMessage, because it's being replaced. It only tests if it gets called, and with the correct argument (however, it's better, and easier, to test onMessage separately, by directly calling it with various arguments from your test cases).
I would guess that the problem is caused by using Object.freeze on the object that you would like to spy on.
Most of the time these "spy on" techniques work by overwriting the spied upon function with another function that implements the "spying" functionality (eg: keeps track of the function calls).
But if you're freezing the object, then the function cannot be overwritten.

Categories

Resources