Testing puppeteer with Jasmine? - web-scraping

We have a website that has many paths of flow (login , signup , payment ,etc)
We're using puppeteer scripts ( typescript via node) to automate-testing our website behaviour (full flow) , and when we get an error (or unexpected result) we're sending email or some kind of alerts.
But I see that people also use jasmine with puppeteer.
For example :
const puppeteer = require('puppeteer');
describe("Jasmine puppeteer", function() {
let browser;
let page;
beforeAll(() => {
browser = await puppeteer.launch({headless: false});
page = await browser.newPage();
await page.goto('chrome://newtab');
await page.screenshot({path: 'a.png'});
})
it("jasmine puppeteer", () => {
expect(await page.title()).toBe("");
done();
});
afterAll(() => {
})
});
Using a testing framework over automated testing framework seems (to me) like Test(Test())
Question
Should we change our site approach testing to jasmin over puppeteer ? I mean , currently puepetteer provides a good way to test our site flow. Should we need to apply jasmine testing over our existing tests scripts ? I'm a bit confused about that.

You can use jest with puppeteer for end to end testing. Jest is based on Jasmine framework. It is developed by Facebook and it’s quite popular now.

puppeteer is not a testing framework.
puppeteer is a tool that automate browser.
you cannot make any assert with puppeteer, so you need a testing framework.
a good choise for puppeteer is jest,
because jest come out of the box with everything you need.
you can also use mocha and chai,
but i suggest jest because you can start to use immediately.

Related

What is the difference between axios and useFetch (nuxt 3)?

I'm slowly starting to migrate from nuxt 2 to nuxt 3.
Previously I used to use axios.
In Nuxt3, it is recommended to use useFetch
However the behavior is quite weird with useFetch. Calls are not made systematically.
For example in this piece of code :
async mounted() {
const store = useAuth();
let response = await axios.get('http://dev.test.fr/api/secured/admin', {headers : store.authHeader() });
this.sensibleInformation = response.data;
},
With Axios, every time I open this page, the call is made and the sensibleInformation is up to date.
With useFetch, the syntax is similar
async mounted() {
const store = useAuth();
let response = await useFetch('http://dev.malt.fr/api/secured/admin' , {method : 'get', headers : store.authHeader() });
this.sensibleInformation = response.data;
},
But the call to the server is done... sometimes. So, the sensibleInformation is most of the time empty. And I don't find any explanation in the documentation.
Maybe there is something I miss here.
I'm using nuxt 3.0.0-rc.6
As it is explained in nuxtJS3 useFetch
useFetch is a wrapper for $fetch(come from here ohmyfetch)
you don't need to import this lib it is include in vuejs3 and lastly axios was not compatible with vuejs3 explained here why use $fetch
what is really great is that body is automatically parsed in JSON, so no need to parse or stringify anything. Also header for content type is automatically added.
So no need to import any library, automatic parsing, automatic header detected etc...
Not sure about this one, but I think the "useFetch" helper is designed to be used with the Vue composition API, so :
within the "setup" function
directly in your script tag if you're using the "<script setup>" synthax
The issue you are dealing with maybe due to the fact that you're using "useFetch" within the "mounted" hook of Vue.js options API.
But once again, not sure about this one :)
The major difference between useFetch and Axios is that useFetch is a wrapper around useAsyncData (and native $fetch) and so works with both SSR and Static modes of Nuxt.
If using it in the onMounted hook you will probably get more expected results if you set the server option to false so it runs only in the client (more like how Axios runs in the mounted hook). I have predominantly used it in <script setup> for SSR set ups.
More info here: https://v3.nuxtjs.org/api/composables/use-fetch

Multi user e2e testing with puppeteer

I am looking for a product that would allow me simulate/test multiple (more than two) users, each logged in to their account, use a web application.
Having multiple users in the test is not to simulate high load as is the case of stress testing; nor it is to make for shorter test time with parallel testing. The reason is to test if the application behaves correctly when users interact with each other.
So basically each user will have their own session cookie sent with ajax or ordinary GET and POST requests they send.
The users each could live in a separate window or be in an iframe on a single page.
Reading through these issues I could not say for sure if this is possible in the latest version of puppeteer or not. Can this be achieved?
Issues:
https://github.com/pyppeteer/pyppeteer/issues/5
https://github.com/puppeteer/puppeteer/issues/4413
If I understand correct, you need some e2e tests for such cases?
I'm using puppeteer as test framework + Jest as test runner ( both updated to the latest version). In some tests-suites I have more than 3 test cases where I need separately logged users in separate browsers + some test cases where 2 different users interacting with each other.
As example, you can create different pages with :
const createIncognitoPage = async () => {
const newPage = await page
.browser()
.createIncognitoBrowserContext()
.then(c => c.newPage());
return newPage;
};
After that you can use it in your test suite :
let clientPage: Page;
it('waitForClientElement', async () => {
clientPage = await createIncognitoPage();
clientpage.goto('url')
clientPage.waitFor(element);
});
let adminPage: Page;
it('waitForSomeoneAnotherElement', async () => {
adminPage = await createIncognitoPage();
await adminPage.goto('adminpageUrl'
});
// then you can iterate between created pages and close em if needed
It's a very simple example. You can iterate between pages and etc. Also create pages in beforeAll block. Hope this will help!

Why is Puppeteer failing simple tests with: "waiting for function failed: timeout 500ms exceeded"?

While trying to set up some simple end-to-end tests with Jest and Puppeteer, I've found that any test I write will inexplicably fail with a timeout.
Here's a simple example test file, which deviates only slightly from Puppeteer's own example:
import puppeteer from 'puppeteer';
describe('Load Google Puppeteer Test', () => {
test('Load Google', async () => {
const browser = await puppeteer.launch({
headless: false
});
const page = await browser.newPage();
await page.goto('https://google.co.uk');
await expect(page).toMatch("I'm Feeling Lucky");
await browser.close();
});
});
And the response it produces:
TimeoutError: Text not found "I'm Feeling Lucky"
waiting for function failed: timeout 500ms exceeded
I have tried adding in custom timeouts to the goto line, the test clause, amongst other things, all with no effect. Any ideas on what might be causing this? Thanks.
What I would say is happening here is that using toMatch expects text to be displayed. However, in your case, the text you want to verify is text associated with a button.
You should try something like this:
await expect(page).toMatchElement('input[value="I\'m Feeling Lucky"]');
Update 1:
Another possibility (and it's one you've raised yourself) is that the verification is timing out before the page has a chance to load. This is a common issue, from my experience, with executing code in headless mode. It's very fast. Sometimes too fast. Statements can be executed before everything in the UI is ready.
In this case you're better off adding some waitForSelector statements throughout your code as follows:
await page.waitForSelector('input[value="I\'m Feeling Lucky"]');
This will ensure that the selector you want is displayed before carrying on with the next step in your code. By doing this you will make your scripts much more robust while maintaining efficiency - these waits won't slow down your code. They'll simply pause until puppeteer registers the selector you want to interact with / verify as being displayed. Most of the time you won't even notice the pause as it will be so short (I'm talking milliseconds).
But this will make your scripts rock solid while also ensuring that things won't break if the web page is slower to respond for any reason during test execution.
You're probably using 'expect-puppeteer' package which does the toMatch expect. This is not a small deviation. The weird thing is that your default timeout isn't 30 seconds as the package's default, check that.
However, to fix your issue:
await expect(page).toMatch("I'm Feeling Lucky", { timeout: 6000 });
Or set the default timeout explicitly using:
page.setDefaultTimeout(timeout)
See here.

PhantomJS cutting/splitting words in half across page breaks

I am using the phantomjs-node api to render a PDF. The problem is that words that appear near the end of a page are split across 2 pages, half the word on page 1, other half on page 2. I cannot understand why this is happening. What can I do to fix this? I already created an issue on phantomjs github with no response yet.
The length of data is unknown until runtime so I don't see it being feasible to put a hard page break in the rows of data.
Which version of PhantomJS are you using?
phantomjs-node ^v2.1.21
What steps will reproduce the problem?
a. Create multi page website
b. Render as pdf
Which operating system are you using?
windows 10 x64
Did you use binary PhantomJS or did you compile it from source?
phantomjs-node pre-compiled
Please provide any additional information below.
As of 2018-05-03 (Mar. 3) the development of PhantomJS is suspended due to lack of active contribution and it is archived. Link
Because of this update, I recommend Google's official headless wrapper around Chrome, puppeteer.
Install:
npm i puppeteer
Usage:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({path: 'example.png'});
await browser.close();
})();
Note
This answer won't provide a helpful answer to your question, but sadly, you'll face the fact, that you have to leave PhantomJS and switch to another headless solution, sooner or later... Our team have faced with this issue, we chose puppeteer.

Google Map Javascript API in react-native

Is it possible to use the javascript api without entirely being dependent to browser DOM to render the map, since react-native use View I feel it's possible to use the api somehow, The method on which to make the api available by passing to global windows also might be possible using fetch, but I don't know how to initiate the callback. If any one got idea how this can work, please share some thoughts
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
</script>
The googlemaps node module #sunilp mentioned only gives you static maps, which are easy to build without relying on a lib, just search for google maps api static maps (don't have enough reputation to post more than two links).
For Android you have this:
https://github.com/teamrota/react-native-gmaps
For iOS there's this, but it cautions it's a work in progress (it also hasn't been updated in months): https://github.com/peterprokop/ReactNativeGoogleMaps
Looking around, it seem your best (supported) bet for iOS today is to use React Native's own MapView if you search their docs. Then, you can make fetch calls to the Google Maps API services for the data, then populate MapView through its interface. Make sure you pass in your key and use https in your url otherwise the service will deny your call:
fetch(
'https://maps.googleapis.com/maps/api/directions/json?origin=41.13694,-73.359778&destination=41.13546,-73.35997&mode=driver&sensor=true&key=[YOUR_KEY]'
)
.then(
(response) => response.text()
)
.then(
(responseText) => {
console.log(responseText);
}
)
.catch(
(error) => {
console.warn(error);
}
);
`
Use node approach of rendering, not yet tried , but looks like it can be done with node-googlemaps
npm install googlemaps
usage
var GoogleMapsAPI = require('googlemaps');
var publicConfig = {
key: '<YOUR-KEY>',
stagger_time: 1000, // for elevationPath
encode_polylines: false,
secure: true, // use https
proxy: 'http://127.0.0.1:9999' // optional, set a proxy for HTTP requests
};
var gmAPI = new GoogleMapsAPI(publicConfig);
you can refer https://github.com/moshen/node-googlemaps

Resources