TestCafe - How Do I Use Roles with auth0 login - testing

I have an app with an auth0 login. I haven't been able to figure out how to make t.useRole in this scenario.
Fortunately, this is easy to reproduce. auth0 (the application) uses the same process. It fails the exact same way as my app.
Expected Outcome
- User logs in
- User goes to dashboard
- User remains log in
- User goes to dashboard again (second test)
Actual
- User logs in
- User goes to dashboard
- User is no longer authenticated
- User goes to login page
import { Role, Selector, ClientFunction } from 'testcafe';
const getPageUrl = ClientFunction(() => window.location.href.toString());
const exampleRole: Role = Role('https://auth0.com/auth/login', async t => {
const userNameInput = Selector('input').withAttribute('name', 'email');
const passwordInput = Selector('input').withAttribute('name', 'password');
const loginButton = Selector('button').withAttribute('name', 'submit');
await t
.wait(5000)
.click(userNameInput)
.typeText(userNameInput, userName)
.click(passwordInput)
.typeText(passwordInput, password)
.click(loginButton);
})
fixture(`SAMPLE`)
.page('https://manage.auth0.com/dashboard')
.beforeEach(async t => {
await t.useRole(exampleRole)
})
test('My first test', async t => {
await t
.expect(getPageUrl()).contains('dashboard')
});
test('My next test', async t => {
await t
.expect(getPageUrl()).contains('dashboard')
})
Output
SAMPLE
√ My first test
× My next test
1) AssertionError: expected
'https://auth0.auth0.com/login?state=***&client=***&protocol=oauth2&response_type=code&redirect_uri=https%3A%2F%2Fmanage.auth0.com%2Fcallback&scope=openid%20profile%20name%20email%20nickname%20created_at'
to include 'dashboard'
```

I had a similar issue reported here: Testcafe: Is there a way to keep the logged-in session intact between pages?
The workaround was to add a wait after .click(loginButton) in the Role block and set presreveUrl to true.
const exampleRole: Role = Role('https://auth0.com/auth/login', async t => {
const userNameInput = Selector('input').withAttribute('name', 'email');
const passwordInput = Selector('input').withAttribute('name', 'password');
const loginButton = Selector('button').withAttribute('name', 'submit');
await t
.wait(5000)
.click(userNameInput)
.typeText(userNameInput, userName)
.click(passwordInput)
.typeText(passwordInput, password)
.click(loginButton);
.wait(10000);
}, { preserveUrl: true });
**Edited to include preserveUrl: true. Thanks #dapperdan1985.

Related

TypeScript Playwright: Saving Storagestate via Sign in via API request and then using inside BowserContext does not work - takes me back to login page

I need to decide whether to go with Playwright as an E2E Automation tool or not.
The following piece of code using backend API for sign in is working fine.
But when I use the saved Storagestate file inside the BrowserContext, then it fails to sign me in, hence taking me back to the Login page.
test.describe('User login', async () => {
var browser: any;
test.beforeEach(async () => {
browser = await chromium.launch({
channel: 'chrome',
headless: false
});
});
const requestContext = await request.newContext();
const response = await requestContext.post(`${testConfig.envConfig.apiURL}/login/authorize`, {
form: {
'email': 'user.tech+admin#xxxx.com',
'password': 'xxxxxx'
}
});
const responseJson = await response.json();
console.log(responseJson);
expect(response.ok()).toBeTruthy();
// Save signed-in state.
await requestContext.storageState({ path: './.storagestates/adminUserStorageState.json' });
await requestContext.dispose();
// Using the Storagesate in the BrowserContext
// page should sign in as a admin user.
test.use({ storageState: './.storagestates/adminUserStorageState.json' });
test('Version 1: Cookies stored via Auth. by backend API', async ({ page }) => {
let url = `/brand/f99f06fb1f121234aaf/gallery`;
await page.goto(url, {timeout: 60000});
});
test('Version 2: Cookies stored via Auth. by backend API', async () => {
// page should sign in as a buyer user.
const userContext = await browser.newContext({ storageState: './.storagestates/buyerUserStorageState.json' });
const page = await userContext.newPage();
await page.goto(`/`, {timeout: 60000});
});
});

Is it possible to mock responses during a detox end-to-end test

I'm currently making a react-native mobile application. I try to test my login button and fields and want to test the logic of moving to the account screen upon login.
Currently I got this as my testcase:
import {clickAccountButton} from "./Navigation";
//API
import nock from "nock";
import {API_URL} from "#env";
import {axiosPost} from "../app/config/api";
jest.useFakeTimers();
describe('LoginScreen tests', function () {
beforeAll(async () => {
await device.launchApp();
});
it('should show the login screen', async () => {
await clickAccountButton();
await expect(element(by.id('loginScreen'))).toBeVisible();
});
it('should have the header', async () => {
await expect(element(by.id('header'))).toBeVisible();
});
it('should contain email and password form field', async () => {
await expect(element(by.id('email'))).toBeVisible();
await expect(element(by.id('password'))).toBeVisible();
});
it('should contain the login and forgotten password buttons', async () => {
await expect(element(by.id('loginSubmit'))).toBeVisible();
await expect(element(by.id('forgotPassword'))).toBeVisible();
});
it('should navigate to ForgotPassword onPress', async () => {
await element(by.id('forgotPassword')).tap();
await expect(element(by.id('forgotPasswordScreen'))).toBeVisible();
//Click the account button again to return to the login screen
await clickAccountButton();
});
it('should login successfully', async () => {
//Give the following response to the next httpRequest
nock(`${API_URL}`)
.post('/api/v1/auth/login')
.reply(200, {
loggedIn: true,
user: {
id: 1,
}
}).persist();
await element(by.id('email')).replaceText('hello#email.com');
await element(by.id('password')).replaceText('foobar');
await element(by.id('loginSubmit')).tap();
//Double check: Check if the view with testID 'welcomeScreen' is showing
//and the input field with testID 'email' is gone
await expect(element(by.id('accountScreen'))).toBeVisible();
await expect(element(by.id('email'))).not.toBeVisible();
});
});
I expect the 'should login successfully' case to succeed because i'm intercepting the request and nock sends a response. This is not the case though. Instead it just does the actual request to my local API server which I don't want to use. Cause I don't want actual login details in my test.
Does anyone know how to handle this? Thanks in advance!
Jest and the app under test run in separate processes so normal Jest mocking techniques such as Nock won't work. Have a look at the mocking guide for Detox.
If you have a module such as apiClient.js in your app then you can mock that with something like apiClient.mock.js.

How to test rest api expecting receive an object?

I'm learning tests and using :
Express
Jest
SuperTest
Sequelize
This is user.test.js, Everytime I ran the test, it create a user object in database, in app.get("/"),I have a:
User.findAll({});
so I would like to test someting more "generic" like a User Object, its possible, what do you suggest me?
const app = require("../app");
const request = require("supertest");
const { User } = require("../models/");
const db = require("../models");
describe('User Model', () => {
beforeAll(async () => {
const user = await db.User.create({ name: "Paulo", email: "blablblalbalbal#gmail.com", password: "123mudar" });
return user
})
it('List User', async () => {
const res = await request(app).get("/");
expect(res.body).toBe(user);
expect(res.statusCode).toBe(200);
});
});
You should mock your calls to DB or anywhere outside of your testing area.

Can't log in through Facebook using Puppeteer - Error: Cookies required

This is my code to login using facebook to a website I'm automating:
const loginButton = await page.waitForXPath(
"//button[contains(#name, 'login')]"
);
const email = await page.waitForSelector("#email");
const pass = await page.waitForSelector("#pass");
await page.evaluate((text) => {
email.value = text;
}, "my email");
await page.evaluate((text) => {
pass.value = text;
}, "my password");
await loginButton.click();
Usually it works well, but once every 4 or 5 times, I get the following error after clicking the loginButton:
"Cookies required. Cookies are not enabled on your browser. Please enable cookies in your browser preferences to continue."
I changed from Chromium to Chrome to see if this would solve the issue, but it didn't work.
I also checked the cookies settings and they are enabled.
The problem was that the inputs were being filled to quickly and facebook was suspecting that I wasn't a real person. I solved it by introducing some delay between the login steps:
const loginButton = await page.waitForXPath(
"//button[contains(#name, 'login')]"
);
const email = await page.waitForSelector("#email");
const pass = await page.waitForSelector("#pass");
await page.waitFor(1000);
await page.evaluate((text) => {
email.value = text;
}, "casas.farach#yahoo.com");
await page.waitFor(1000);
await page.evaluate((text) => {
pass.value = text;
}, "789654123");
await page.waitFor(1000);
await loginButton.click();

How to use c8yClient code in the Angular 6 App (typescript file)

For Example:
import { Client } from '#c8y/client';
const baseUrl = 'https://demos.cumulocity.com/';
const tenant = 'demos';
const user = 'user';
const password = 'pw';
(async () => {
const client = await Client.authenticate({
tenant,
user,
password
}), baseUrl);
const { data, paging } = await client.inventory.list();
// data = first page of inventory
const nextPage = await paging.next();
// nextPage.data = second page of inventory
})();
Consider that I have login module in an angular 6 application. How to use this above code and authenticate the user in the login.component.ts file?
Cumulocity has released a demo on Stackblitz how to log in the user. Basically you build a ngForm with username, password and tenant and pass that to the Cumulocity client:
async login() {
const client = new Client(new BasicAuth(
{
user: this.model.user,
password: this.model.password,
tenant: this.model.tenant
}),
`https://${this.model.tenant}.cumulocity.com`
);
try {
let user = await client.user.current();
this.cumulocity.client = client;
} catch (ex) {
this.cumulocity.client = null;
this.error.shown = true;
this.error.msg = ex.message;
}
}
In this case this.model is the data coming from an ngFrom and on button click the login()? function is executed. The this.cumulocity variable contains a service so that you can share the logged in client with other components.
Note: If you run this on a different server (not hosted), then you need to enable CORS in the Cumulocity administration.