Multi user e2e testing with puppeteer - automated-tests

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!

Related

Firebase & Flutter (on Android) - MessagingToken is null

I'm running into trouble with some of my app's subscribers. We recently introduced the ability to send out notifications to our users using FirebaseMessaging. I should also mention that the app is on Android only.
Here is a brief section of code that we are running
updateUser(Userx user) async {
var messagingToken = await FirebaseMessaging.instance.getToken();
var packageInfo = await PackageInfo.fromPlatform();
user.messagingToken = messagingToken!;
user.appVersion = packageInfo.version;
await Users.updateUser(user);
}
It turns out that the FirebaseMessaging.instance.getToken() sometimes returns null and I can't figure out why that would be the case. The documentation also doesn't say much.
Could this be device specific? Maybe a user-setting to not allow any in-app messages?
A potential workaround is of course to null-check the token and simply accept it being null but I would like to understand the reasons behind that.
I found one more method that could be helpful, but I'm unsure about it.
Call FirebaseMessaging.instance.isSupported() first and act based on the result.

Flutter dynamic links test

Edited Question :
I have an issue with Firebase Dynamic Links Packag , My goal is getting know if new user installed and opend my app for first time to give him a rewards like 10 point . I tried to search everywhere but no answer,in firebase website there is option to know if user install for first time.
My Goal is : Getting value for first time install & how to debug this code ?
initDynamicLinks when app Lanched :
void initDynamicLinks() async {
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
final Uri deepLink = dynamicLink?.link;
if (deepLink != null) {
Navigator.pushNamed(context, deepLink.path);
}
},
onError: (OnLinkErrorException e) async {
print('onLinkError');
print(e.message);
}
);
final PendingDynamicLinkData data = await FirebaseDynamicLinks.instance.getInitialLink();
final Uri deepLink = data?.link;
if (deepLink != null) {
Navigator.pushNamed(context, deepLink.path);
}
}
.
You're mixing two things here.
The First-opens tab gives you the number of unique users who clicked on your Firebase Dynamic Link for the first time.
If you want to know how many unique users used your app, by clicking the Firebase Dynamic Link or not to get to your app, you have to implement the Firebase Analytics plugin to your app.
This way you'll get access to Dashboards showing you how many Unique users you have.
EDIT
Reading your comment, looks like your question is not related to your problem.
What you want here is to attribute rewards for users who invited their friends thanks to a referral link.
Since I never implemented this witout a dedicated backend, the only thing I can share is a use-case I used some time ago explaining the logic to follow to implement it.
https://firebase.google.com/docs/dynamic-links/use-cases/rewarded-referral
EDIT 2
The logic explained in the documentation is the following :
1- Generate a Dynamic Link for UserA.
2- UserA sends the Dynamic Link to someone (called UserB).
3- When UserB starts the app from a Dynamic Link, retrieve the referral informations in the app (to retrieve UserA's informations)
4- Call a route on your backend to attribute the reward to UserA (and check if UserB is really a new user in your database).
The point is, you shouldn't manage a referral/referrer relationship on the client's side (it would be way too easily abused/hacked).
It's the job of a backend (or cloud function) to manage this.
Once you have received the link clickthrough in your app use the google_analytics package to log an event.
Related thread here:
Flutter log event with google analytics
To be honest i have never used Firebase Dynamic Links , But if your Goal is to Achieve a first open or login token , you can always use the Sharedpreferences package , in my case iam using it to navigate to different pages passed on the first login value .
i think that Sharedpreferences is more reliable and easier than what you are trying to achieve with firebase
UPDATE:
what you actually want to do is make a firebase collection with IMEI numbers , when there is a new IMEI that means a new user , when that IMEI is in your collection that means that the app is not installed for the first time ,
you can use this package imei_plugin to get IMEI number and store it on firebase

How can I get the total number of active installs for my app on firebase?

The first display in the Analytics Dashboard on Firebase shows total active users.
My understanding is that this is showing the amount of users who use the app within a given period.
However, some of these users may have since uninstalled the app. Is there a separate number which shows the number of total installs?
I simply need to know the number of users who have my app actively installed at any given time.
Active installs of the app, not necessarily the number of authenticated users.
Looking through the firebase API, this webpage will be you're best bet
https://firebase.google.com/docs/auth/admin/manage-users
Scrolling down it has a section labled "List all users"
not for sure what language you're using but in Node.js it is
function listAllUsers(nextPageToken) {
// List batch of users, 1000 at a time.
admin.auth().listUsers(1000, nextPageToken)
.then(function(listUsersResult) {
listUsersResult.users.forEach(function(userRecord) {
console.log('user', userRecord.toJSON());
});
if (listUsersResult.pageToken) {
// List next batch of users.
listAllUsers(listUsersResult.pageToken);
}
})
.catch(function(error) {
console.log('Error listing users:', error);
});
}
// Start listing users from the beginning, 1000 at a time.
listAllUsers();
The above will make sure you have a list off all authenticated users. Simply combine that with
exports.appUninstall = functions.analytics.event('app_remove').onLog(event => {
const user = event.user; // structure of event was changed
const uid = user.userId; // The user ID set via the setUserId API.
// add code for removing data
});
And remove the userID and decrement the active users by 1 to have a general sense of installed apps.
hopefully this works better.

Testing puppeteer with Jasmine?

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.

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.

Resources