Looking to set custom referrer for my tests with Test Cafe but cannot find right solution for that. On Firefox you can easily change referrer with some plugins but how to do it within Test Cafe ?
You can use the Request Hooks mechanism for this purpose. I created an example to demonstrate this approach:
import { RequestHook } from 'testcafe';
fixture `fixture`
.page `http://example.com`;
export class MyRequestHook extends RequestHook {
constructor (requestFilterRules, responseEventConfigureOpts) {
super(requestFilterRules, responseEventConfigureOpts);
}
async onRequest (event) {
event.requestOptions.headers['Referer'] = 'http://my-modified-referer.com';
}
async onResponse (event) {
}
}
const hook = new MyRequestHook();
test.requestHooks(hook)('referer', async t => {
await t.navigateTo('https://www.whatismyreferer.com/');
await t.debug();
});
Related
Agenda: I wanted to run login method before all tests and Logout method after all tests, so that if the before hook fails, the test execution won't happen.
I added login logic in fixture.before hook as shown in the code below. But it's giving the following error, can some help me to fix it.
Test file
import { Selector } from "testcafe";
import LoginPage from '../page-objects/login.po';
const loginPage = new LoginPage();
fixture`Getting Started`
.page`https://example.com/`
.before(async t => {
await loginPage.login();
});
test("My First Test", async t => {
const str = await Selector('.home-container h1').textContent;
console.log(str);
});
Pageobjects class
import { Selector, t } from 'testcafe';
import CommonFunctions from '../commons/common-fns'
export default class LoginPage{
constructor () {
this.emailTxtBox = Selector('input[type="email"]');
this.nextBttn = Selector('button[type="submit"]');
this.microsoftNextBttn = Selector('input[type="submit"]');
this.passwordTxtBox = Selector('input[type="password"]');
this.signinBttn = Selector('input[type="submit"]');
this.noBttn = Selector('#idBtn_Back');
}
async login() {
await t
.typeText(this.emailTxtBox, '')
.click(this.nextBttn)
.typeText(this.emailTxtBox, '')
.click(this.microsoftNextBttn)
.typeText(this.passwordTxtBox, '')
.click(this.signinBttn)
.click(this.noBttn);
}
}
You have to use beforeEach fixture hook instead of before
https://devexpress.github.io/testcafe/documentation/test-api/test-code-structure.html#fixture-hooks
1. The Problem
The testWidgets function is apparently only a subcase of the test function.
A use case I'm trying to solve right now is to pump the same widget for multiple testWidgets, a setUp for multiple testWidgets. However, how can I do this if it creates a new instance inside each test?
I've tried to initialize a WidgetTester outside the tests, in the main(), but WidgetTester has only a private constructor:
class WidgetTester
extends WidgetController
implements HitTestDispatcher, TickerProvider {
WidgetTester._(TestWidgetsFlutterBinding binding) : super(binding) {
if (binding is LiveTestWidgetsFlutterBinding)
binding.deviceEventDispatcher = this;
}
I don't quite get how the Flutter team made this work, but initializing a WidgetTester in the same way they did inside the testWidgets function isn't working for me:
final TestWidgetsFlutterBinding binding
= TestWidgetsFlutterBinding.ensureInitialized()
as TestWidgetsFlutterBinding;
final WidgetTester tester = WidgetTester._(binding);
2. An Example
A simple example would be to try to break down the tests of the Flutter demo that is created with each new Flutter project from flutter create. In it, we could try to separate the initial setup test of the app from the tapping action test:
testWidgets('Initial setup', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
});
testWidgets('Increment the counter on tap', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
The idea would be to try to move the await tester.pumpWidget(MyApp()); into a setUp function.
Below is what looks like the current way to solve for this in Flutter.
To summarize:
Create the group(..) structure inside main()
Create your own private methods from inside that structure, for each group of testing you want. For each of these private methods:
Pass in the WidgetTester instance
Let them be async
And then you should only have a single call to testWidgets(..)
Inside this method, is where you call the private methods you set up to distribute test logic
Call each of these with await, so they don't run concurrently
So far I didn't find a way for the output to indicate each "sub-test" it ran, so just using print(...) statements for now.
This is a demo for some QR Code logic:
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:qr_code_demo/app/appRoutes.dart';
import 'package:qr_code_demo/view/appHome.dart';
import 'package:qr_code_demo/view/qrScanner.dart';
class MockNavigatorObserver extends Mock implements NavigatorObserver {}
void main() {
group('MainPage navigation tests', () {
NavigatorObserver mockObserver;
_loadAppHomeScreen(WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
routes: AppRoutes.getRouteMap(),
home: AppHomeScreen(),
navigatorObservers: [mockObserver],
),
);
}
setUp(() {
mockObserver = MockNavigatorObserver();
});
Future<Null> _verifyLayoutElements(WidgetTester tester) async {
print('_verifyLayoutElements');
expect(find.byIcon(Icons.scanner), findsOneWidget);
expect(find.byType(FloatingActionButton), findsOneWidget);
expect(find.byType(RaisedButton), findsOneWidget);
}
Future<Null> _navigateToQrScannerScreen(WidgetTester tester) async {
print('_navigateToQrScannerScreen');
await tester.tap(find.byIcon(Icons.scanner));
await tester.pumpAndSettle();
verify(mockObserver.didPush(any, any));
expect(find.byType(AppHomeScreen), findsNothing);
expect(find.byType(QrScannerScreen), findsOneWidget);
}
testWidgets('AppHomeScreen WidgetTester', (WidgetTester tester) async {
await _loadAppHomeScreen(tester);
await _verifyLayoutElements(tester);
await _navigateToQrScannerScreen(tester);
});
});
}
Thanks to:
https://iiro.dev/2018/08/22/writing-widget-tests-for-navigation-events/
Scroll to code for this file: test/navigation_test.dart
====
And double-thanks, because the navigation testing logic including with this example is thanks to #iiro's post: https://stackoverflow.com/a/51983194/2162226
Here is the appRoutes.dart file:
import 'package:qr_code_demo/view/appHome.dart';
import 'package:qr_code_demo/view/qrScanner.dart';
class AppRoutes {
static const String AppHome = 'AppHome';
static const String QrScanner = 'QrScanner';
static String initialRoute() {
return AppHome;
}
static getRouteMap() {
return {
AppRoutes.AppHome: (context) => AppHomeScreen(),
AppRoutes.QrScanner: (context) => QrScannerScreen()
};
}
}
The answer is setUpAll() function. Use it first in the main method, outside of group and it runs only once.
I am new to JS and TestCafe.
Using PageObjects in TestCafe my goal is to launch a login page and authenticate before running a test.
The .open call works fine from fixtures. Also from with .before.
fixture `Check for new emails`
.page `https://www.mail.com/myemails`
and
fixture `Check for new emails`
.page `https://www.mail.com/myemails`
.beforeEach(async t => {
console.log("before");
.page `https://www.mail.com/login`;
myloginScreen.performLogin();
})
test ('', async t => {
await t
console.log("In the test step");
});)
PageObject look like this:
import { Selector, t } from 'testcafe';
export default class LoginPage {
constructor () {
this.loginInput = Selector('input').withAttribute('id','email');
this.passwordInput = Selector('input').withAttribute('id','password');
this.signInButton = Selector('button').withAttribute('class','big-button');
this.userMenu = Selector('a').withAttribute('data-which-id', 'gn-user-menu-toggle-button');
}
async performLogin() {
console.log("function entered")
.typeText(this.loginInput, 'user#mail.com')
.typeText(this.passwordInput, 'password')
.click(this.signInButton);
console.log("Form submitted");
}
}
But I want to move the Login URL load to the PageObject like this:
async performLogin() {
console.log("function entered")
.navigateTo ("https://www.mail.com/login")
await t
.typeText(this.loginInput, 'user#mail.com')
.typeText(this.passwordInput, 'password')
.click(this.signInButton);
console.log("Form submitted");
}
The code calls the function fine but quits the .before and jumps to the test step.
I am not sure what I am doing wrong here, will appreciate any help.
The performLogin is an asynchronous method. So, you need to call it with the await keyword:
fixture `Check for new emails`
.page `https://www.mail.com/myemails`
.beforeEach(async t => {
console.log("before");
await myloginScreen.performLogin();
});
I'm using testcafe to run some tests in an ecommerce page, but a random pop up is breaking the test. When it appears on the window, the Testcafe is unable to click on the next selector and move forward with the test, and then fail.
Currently, I'm using .js files to hold the selectors, like:
import { Selector } from 'testcafe';
export default class Checkout {
constructor () {
//address
this.addressName = Selector('input#CC-checkoutCepAddressBook-sfirstname');
this.addressLastname = Selector('input#CC-checkoutCepAddressBook-slastname');
//Rest of selectors...
}
Then, I import them to another .js and declare the tests like functions:
import { ClientFunction } from 'testcafe';
import { Selector } from 'testcafe';
import Fixture from '../../../DesktopModel/Chrome/fixture.js';
import Home from '../../../DesktopModel/Chrome/home.js';
import Cart from '../../../DesktopModel/Chrome/cart.js';
...
const fixtureUrlBase = new Fixture();
const home = new Home();
const pdp = new Pdp();
const cart = new Cart();
...
export async function checkoutLoggedBoleto(t) {
await t
.click(pdp.addToCartBtn)
.click(home.finishOrderBtn)
.click(cart.finishOrderBtn)
//Rest of the test actions...}
Finally, I'm executing another.js where I declare the tests using test command:
test
.before(async t => {
await login(t);
})
('Desktop - User Login + Checkout with Invoice', async t => {
// Function Login => Search => PDP => Checkout with Invoice
await checkoutLoggedBoleto(t);
});
Since it is a random event (it happens in different moments, like sometimes in the product page and sometimes in the checkout page), is possible to use some conditional test just bypass this popup, like if the pop up 'x' appears on the screen, click on 'close popup' and continue with test, else continue with the test.
I search in testcafe Test API and have not found such a function.
I'm using testcafe 0.17.0.
TestCafe doesn't provide an API for that. To handle you case, you can check whether the popup appears before each action.
Optionally, to make your code cleaner, you can wrap TestCafe API actions in the following way:
import { t, Selector } from 'testcafe';
const closePopupBtn = Selector('.close-popup');
async function checkPopup () {
if(await closePopupBtn.exists)
await t.click(closePopupBtn);
}
const tc = {
click: async selector => {
await checkPopup();
await t.click(selector);
}
}
test('my test', async () => {
await tc.click('.btn1');
await tc.click('.btn2');
});
I would like to test my router which for the sake of simplicity looks as follows:
// app.router.js
import Ember from 'ember';
import config from './config/environment';
const Router = Ember.Router.extend({
location: config.locationType
});
Router.map(function() {
this.route('sessions', function() {
this.route('login');
this.route('logout');
});
this.route('profile');
});
export default Router;
Is it possible to unit-test it?
I tried using acceptance tests but I was not successful:
import Ember from 'ember';
import { test } from 'qunit';
import moduleForAcceptance from 'transformed-admin/tests/helpers/module-for-acceptance';
import startApp from 'transformed-admin/tests/helpers/start-app';
moduleForAcceptance('Acceptance | configuration', {
beforeEach: function() {
this.application = startApp();
},
afterEach: function() {
Ember.run(this.application, 'destroy');
}
});
test('should map routes correctly', function(assert) {
visit('/');
const app = this.application;
andThen(function() {
app.Router.detect("profile"); // false
app.Router.detect("Profile"); // false
const a = app.Router.extend({});
a.detect("profile"); // false
a.detect("Profile"); // false
});
});
What are the best practices here? Do you test Router.map() at all? Or do you rely on testing of concrete routes as a guarantee that the Router.map() is written correctly?
Not quite sure what you want to do. You could write acceptance tests for each route if you want to make sure that they are visible:
import { test } from 'qunit';
import moduleForAcceptance from 'people/tests/helpers/module-for-acceptance';
moduleForAcceptance('Acceptance | login');
test('visiting /', function(assert) {
visit('/');
andThen(function() {
assert.equal(currentURL(), '/index');
assert.equal(currentPath(), 'index');
});
});
test('visiting /profile', function(assert) {
visit('/profile');
andThen(function() {
assert.equal(currentURL(), '/profile');
assert.equal(currentPath(), 'profile');
});
});
You could also write unit tests for your routes.
You should not test Ember.js internals. Ember.Router is covered by tests. You should test your application specific logic (eg. handling a specific action in a route by unit test) and behavior (eq. a specific route exists by acceptance test).