For testing Vue2 I use testcafe.
Command to run tests
testcafe firefox test/e2e/specs/ --app \"npm run dev\"
--app-init-delay 20000 -S -s test/e2e/screenshots
Test file
import { ClientFunction, Selector } from 'testcafe';
const devServer = require('../../../webpack/devServer');
fixture(`Getting Started`)
// Load the URL your development server runs on.
.page(`http://localhost:${devServer.port}/#/login`);
test('test login', async t => {
const userSelector = await new Selector('.login-squere input[type="text"]');
const passSelector = await new Selector('.login-squere input[type="password"]');
const logiIn = await new Selector('.login-squere button');
await t.typeText(userSelector, 'manager')
.typeText(passSelector, 'manager')
.click(logiIn);
});
I expect after .click(logiIn) site to route to /#/projects, but nothing happens
I added to test
await t.typeText(userSelector, 'manager')
.typeText(passSelector, 'manager')
.click(logiIn)
.navigateTo(`http://localhost:${devServer.port}/#/projects`);
And again no result. If I set .page to /#/projects it wil be rerouted to login.
So I can test only login page, because I cant make testcafe route Vue to next view.
This problem appears only if after login click we have ajax. TestCafe doesnt have request handler, so it is better to try something else for e2e
Try this one:
test('login', async t => {
await login(t);
});
and separate your code into a new function:
const login = async t => {
const userSelector = await new Selector('.login-squere input[type="text"]');
const passSelector = await new Selector('.login-squere input[type="password"]');
const logiIn = await new Selector('.login-squere button');
await t.typeText(userSelector, 'manager')
.typeText(passSelector, 'manager')
.click(logiIn);
};
Related
I have this problem, I have some tests of e2e with puppeteer and they are failing because the chrome unsaved changes pop up appears and I do not want them to be saved, do you know how I could eliminate it?
I wanna click on the calcel btn of the pop up, or other way to make it work
Puppeteer has a way of handling alerts. You can Accept or Dismiss it.
https://pptr.dev/api/puppeteer.dialog
Example from the page above
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
page.on('dialog', async dialog => {
console.log(dialog.message());
await dialog.dismiss();
await browser.close();
});
page.evaluate(() => alert('1'));
})();
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();
});
This is a react-native application and I am currently writing some end-to-end testing.
A token is stored in the redux store shown below and I am testing the login functionality using detox/jest. I need to detect if the token exists in the store in my login.spec.js . If the token exists I want to wipe it from the store so the user is not logged in automatically when i reload the app to take the user back to another scene. The main function in question is the refreshUserToken() and line:-
const { refresh_token } = yield select(token);
Here is the redux saga file User.js located at:-MyApp/App/Sagas/User.js
import { call, put, takeEvery, select } from "redux-saga/effects";
import Config from "MyApp/App/Config";
import API from "MyApp/App/Services/API";
import { when } from "MyApp/App/Helpers/Predicate";
import Credentials from "MyApp/App/Helpers/Credentials";
import ActionCreator from "MyApp/App/Actions";
const appendPayload = payload => {
return {
...payload,
// Removed because no longer needed unless for testing purposes.
// username: Config.TEST_USERNAME,
// password: Config.TEST_PASSWORD,
client_id: Config.CLIENT_ID,
client_secret: Config.CLIENT_SECRET,
};
};
const token = state => state.token;
const user = state => state.user;
const attemptUserLogin = function*(action) {
const { payload } = action;
const login = "/oauth/token";
const grant_type = "password";
const loginPayload = appendPayload(payload);
action.payload = {
...loginPayload,
grant_type,
};
yield attemptUserAuthorisation(login, action);
};
const attemptUserRegister = function*(action) {
const register = "/api/signup";
const { payload } = action;
yield Credentials.save(payload);
yield put(ActionCreator.saveUserCredentials(payload));
yield attemptUserAuthorisation(register, action);
};
const refreshUserToken = function*(action) {
const login = "/oauth/token";
const grant_type = "refresh_token";
const { refresh_token } = yield select(token);
action.payload = {
...action.payload,
grant_type,
refresh_token,
};
yield attemptUserAuthorisation(login, action);
};
const watchExampleSaga = function*() {
yield takeEvery(ActionCreator.AUTO_USER_LOGIN, autoUserLogin);
yield takeEvery(ActionCreator.USER_LOGIN, attemptUserLogin);
yield takeEvery(ActionCreator.USER_REGISTER, attemptUserRegister);
yield takeEvery(ActionCreator.USER_REFRESH_TOKEN, refreshUserToken);
};
export default watchExampleSaga;
Here is my detox/jest spec file located at:-MyApp/App/e2e/login.spec.js
describe('Login Actions', () => {
it('Should be able to enter an email address', async () => {
await element(by.id('landing-login-btn')).tap()
const email = 'banker#dovu.io'
await element(by.id('login-email')).tap()
await element(by.id('login-email')).replaceText(email)
});
it('Should be able to enter a password', async () => {
const password = 'secret'
await element(by.id('login-password')).tap()
await element(by.id('login-password')).replaceText(password)
});
it('Should be able to click the continue button and login', async () => {
await element(by.id('login-continue-btn')).tap()
await waitFor(element(by.id('dashboard-logo'))).toBeVisible().withTimeout(500)
// If token exists destroy it and relaunch app. This is where I need to grab the token from the redux saga!
await device.launchApp({newInstance: true});
});
})
This is how I handled a similar scenario:
in package.json scripts:
"start:detox": "RN_SRC_EXT=e2e.tsx,e2e.ts node node_modules/react-native/local-cli/cli.js start",
In my detox config:
"build": "ENVFILE=.env.dev;RN_SRC_EXT=e2e.tsx,e2e,ts npx react-native run-ios --simulator='iPhone 7'",
That lets me write MyFile.e2e.tsx which replaces MyFile.tsx whilst detox is running
In the test version of that component I have buttons which are tapped in the tests and the buttons dispatch redux actions
Looks like this actually cant be done unless someone can give me a solution other than mocking the state which still wouldn't work in this case my app checks for real states to auto login.
I did get to the stage of creating a new action getUserToken and exporting that into my jest file. However the action returns undefined because the jest file requires a dispatch method like in containers.js. If anyone could provide me with a method of this using jest I would be very happy.
I am using Jest and have puppeteer set up as in this repository, which is linked to from the Jest documentation.
I am trying to write some automated smoke tests on a WordPress website using puppeteer. One of the tests attempts to upload an image to the WordPress Media Library.
This is the test:
it('Create test media', async () => {
// go to Media > Add New
await page.goto(`${env.WP_HOME}/wp/wp-admin/media-new.php`)
const display = await page.evaluate(() => {
const el = document.querySelector('#html-upload-ui')
return window.getComputedStyle(el).display
})
if (display !== 'block') {
// ensure we use "built-in uploader" as it has `input[type=file]`
await page.click('.upload-flash-bypass > a')
}
const input = await page.$('#async-upload')
await input.uploadFile(testMedia.path)
})
The file input field's value is populated as expected (I know this because if I save out a screenshot after the call to uploadFile it shows the path of the file in the input), and the form is submitted, however when I go to view the media library there are no items.
I have tried the following amendments to the uploadFile part of the test, to no avail:
// 1. attempt to give time for the upload to complete
await input.uploadFile(testMedia.path)
await page.waitFor(5000)
// 2. attempt to wait until there is no network activity
await Promise.all([
input.uploadFile(testMedia.path),
page.waitForNavigation({waitUntil: 'networkidle0'})
])
// 3. attempt to submit form manually (programmatic)
input.uploadFile(testMedia.path)
page.evaluate(() => document.querySelector('#file-form').submit())
await page.waitFor(5000) // or w/ `waitForNavigation()`
// 4. attempt to submit form manually (by interaction)
input.uploadFile(testMedia.path)
page.click('#html-upload')
await page.waitFor(5000) // or w/ `waitForNavigation()`
The problem is that file uploading doesn't work when connecting to a Browser instance via WebSocket as in jest-puppeteer-example. (GitHub issue here: #2120.)
So instead of doing that just use puppeteer.launch() directly when setting up your test suite (instead of via the custom "Jest Node environment"):
let browser
, page
beforeAll(async () => {
// get a page via puppeteer
browser = await puppeteer.launch({headless: false})
page = await browser.newPage()
})
afterAll(async () => {
await browser.close()
})
You also then have to manually submit the form on the page, as in my experience uploadFile() doesn't do this. So in your case, for the WordPress Media Library single file upload form, the test would become:
it('Create test media', async () => {
// go to Media > Add New
await page.goto(`${env.WP_HOME}/wp/wp-admin/media-new.php`)
const display = await page.evaluate(() => {
const el = document.querySelector('#html-upload-ui')
return window.getComputedStyle(el).display
})
if (display !== 'block') {
// ensure we use the built-in uploader as it has an `input[type=file]`
await page.click('.upload-flash-bypass > a')
}
const input = await page.$('#async-upload')
await input.uploadFile(testMedia.path)
// now manually submit the form and wait for network activity to stop
await page.click('#html-upload')
await page.waitForNavigation({waitUntil: 'networkidle0'})
})
I have read the documentation and I have followed the tutorial step by step and I only have managed to run the app.
Documentation: http://electron.atom.io/docs/tutorial/using-selenium-and-webdriver/
The connection with chromedriver I cannot make it work, when I launch the test and try click a simple button I get this:
Error: ChromeDriver did not start within 5000ms at Error (native)
at node_modules/spectron/lib/chrome-driver.js:58:25 at
Request._callback (node_modules/spectron/lib/chrome-driver.js:116:45)
at Request.self.callback
(node_modules/spectron/node_modules/request/request.js:200:22) at
Request.
(node_modules/spectron/node_modules/request/request.js:1067:10) at
IncomingMessage.
(node_modules/spectron/node_modules/request/request.js:988:12) at
endReadableNT (_stream_readable.js:913:12) at _combinedTickCallback
(internal/process/next_tick.js:74:11) at process._tickCallback
(internal/process/next_tick.js:98:9)
My code:
"use strict";
require("co-mocha");
var Application = require('spectron').Application;
var assert = require('assert');
const webdriver = require('selenium-webdriver');
const driver = new webdriver.Builder()
.usingServer('http://127.0.0.1:9515')
.withCapabilities({
chromeOptions: {
binary: "./appPath/app"
}
})
.forBrowser('electron')
.build();
describe('Application launch', function () {
this.timeout(100000);
var app;
beforeEach(function () {
app = new Application({
path: "./appPath/app"
});
return app.start();
});
afterEach(function () {
if (app && app.isRunning()) {
return app.stop();
}
});
it('click a button', function* () {
yield driver.sleep(5000);
yield driver.findElement(webdriver.By.css(".classSelector")).click();
});
});
Thanks and sorry for my English.
I recommend you to use Spectron. which is a less painful way of testing your electron app. in my opinion perfect combination is using it with Ava test framework, which allows the concurrently test.
async & await is also another big win. which allows you to have so clean test cases.
and also if you have a test which needs to happen serial, you can use test.serial
test.serial('login as new user', async t => {
let app = t.context.app
app = await loginNewUser(app)
await util.screenshotCreateOrCompare(app, t, 'new-user-mission-view-empty')
})
test.serial('Can Navigate to Preference Page', async t => {
let app = t.context.app
await app.client.click('[data-test="preference-button"]')
await util.screenshotCreateOrCompare(app, t, 'new-user-preference-page-empty')
})
and just for reference; my helper test cases.
test.before(async t => {
app = util.createApp()
app = await util.waitForLoad(app, t)
})
test.beforeEach(async t => {
t.context.app = app
})
test.afterEach(async t => {
console.log('test complete')
})
// CleanUp
test.after.always(async t => {
// This runs after each test and other test hooks, even if they
failed
await app.client.localStorage('DELETE', 'user')
console.log('delete all files')
const clean = await exec('rm -rf /tmp/DesktopTest')
await clean.stdout.on('data', data => {
console.log(util.format('clean', data))
})
await app.client.close()
await app.stop()
})
util function,
// Returns a promise that resolves to a Spectron Application once the app has loaded.
// Takes a Ava test. Makes some basic assertions to verify that the app loaded correctly.
function createApp (t) {
return new Application({
path: path.join(__dirname, '..', 'node_modules', '.bin',
'electron' + (process.platform === 'win32' ? '.cmd' : '')),
// args: ['-r', path.join(__dirname, 'mocks.js'), path.join(__dirname, '..')],
env: {NODE_ENV: 'test'},
waitTimeout: 10e3
})
}
First off, Spectron (which is a wrapper for WebdriverIO) and WebdriverJS (which is part of Selenium-Webdriver) are two different frameworks, you only need to use one of them for your tests.
If you are using WebdriverJS, then you need to run ./node_modules/.bin/chromedriver in this step: http://electron.atom.io/docs/tutorial/using-selenium-and-webdriver/#start-chromedriver
I could get ChromeDriver working by adding a proxy exception in my terminal.
export {no_proxy,NO_PROXY}="127.0.0.1"