I have a test suite(fixture) with multiple functional tests for test cafe. They look something like this:
fixture('Test suite')
.page(login_url)
.beforeEach(async (t) => {
await t.maximizeWindow()
await page.signIn('username', 'pass');
});
test('Test case 1', async (t) => {
await t.expect(page.title.textContent).eql('My Page');}
test('Test case 2', async (t) => {
await do some other stuff}
This obviously wastes a lot of time before each test because we need to log in each time.
How do I log in once, set that page as an entry point, and start each test from that page?
You can use the TestCafe Roles mechanism to log in only once. All further tests will not require additional authentication. Take a look at the following article for details: https://devexpress.github.io/testcafe/documentation/guides/advanced-guides/authentication.html#user-roles
Related
I'm using Jest for testing some API endpoints, but these endpoints might fail falsy at some times, because of network issues and not my program bugs. So I want to do the test again multiple times (5 times for example) with a delay, and if all of these tries failed, Jest should report a failure.
What is the best way to achieve this? Does Jest or other libraries provide a solution? Or should I write my own program with something like setInterval?
For testing you should not ideally be making network calls as they slow down your tests. Moreover you might be communicating to an external API which ideally should not be part of your test code. Also can lead to false negatives as already observed by you. You can do something like below:
async function getFirstMovieTitle() {
const response = await axios.get('https://dummyMovieApi/movies');
return response.data[0].title;
}
For testing above network call you should mock your axios get request in your test. To test the above code, you should
jest.mock('axios');
it('returns the title of the first movie', async () => {
axios.get.mockResolvedValue({
data: [
{
title: 'First Movie'
},
{
title: 'Second Movie'
}
]
});
const title = await getFirstMovieTitle();
expect(title).toEqual('First Movie');
});
Try to read more about mocking in jest to understand better
I am using Mocha and Chai to test my async js code.
I need to wait for previous tests to complete before starting the next test.
ex] create account -> update account -> delete account
Here is a simplified version of the test code:
describe('Account Tests', function() {
this.timeout(30000);
// I want to run this 1st
it('should create account', async function() {
let account = await api.acount.create();
expect(account).not.to.be.null;
})
// I want to run this 2nd
it('should update account', async function() {
let accountUpdate = await api.account.update();
expect(accountUpdate.status).to.equal(204);
})
// I want to run this last
it('should delete account', async function() {
let result = await api.account.remove();
expect(result).to.be.true;
})
})
Since I am using promises with async & await, the promise is inherently returned to 'it'
The problem I am encountering is sometimes the account is created then deleted before the update test can run. So, the update test fails while the create & delete tests pass. Sometimes the delete test tries to run before the create test is finished and so fails. I know I can add a sleep in between these tests, but I don't want to use a 'hack' when there is a real solution.
I'm new using Mocha and Chai, and I must be missing something here, but shouldn't the promise make the creating an account test wait until that is finished before running the update test?
I'm currently facing an issue where awaiting a TestCafe ClientFunction within a assertion query chain leads to the behavior demonstrated by the code below:
const getPageUrl = ClientFunction(() => window.location.href.toString());
// This test works fine
test("Test that works as expected", async t => {
await t
.click(pageElements.someNaviButton) // navigates me to the site with url extension /some/url
.expect(getPageUrl()).contains("/some/url")
});
// This test works fine as well
test("Another test that works as expected", async t => {
await t.click(pageElements.someNaviButton) // navigates me to the site with url extension /some/url
const myPageUrl = await getWindowLocation();
await t.expect(myPageUrl).contains("/some/url")
});
// This test fails
test("Test that does not work as expected", async t => {
await t
.click(pageElements.someNaviButton)
.expect(await getPageUrl()).contains("/some/url")
});
According to TestCafe's documentation, one has to await asynchronous ClientFunctions. This leads me to what irritates me: I expect the second test to pass, which it does. Awaiting the method that encapsulates the ClientFunction within the expect method of the third test seems to be problematic, but why is that?
Additional info that could be of interest: I'm using TestCafe version 1.14.0.
Please consider that a test actions chain is a single expression. So, in the third test, getPageUrl is calculated before the chain execution. At that moment, the test is still on the start page.
The first test passes because getPageUrl is calculated lazily via TestCafe Smart Assertion Query Mechanism. This is the most proper way to write this kind of tests.
The second test passes because you broke the test actions chain.
So I'm getting better with testcafe and one feature I'd like to learn is its RequestLogger.
So I've created an instance of it
import { RequestLogger } from 'testcafe';
const logger = RequestLogger(/some reg exp/, {
logRequestHeaders: true,
logRequestBody: true
});
export default logger;
and then tried to use it on a sample test fixture:
fixture `REQUEST LOGGER TEST`
.requestHooks(logger);
test('should contain 204 as a status code 1', async t => {
await t.useRole(role);
await model.doSmth(t);
await model.doSmthElse(t);
console.log(logger.requests);
await t
.expect(logger.requests[0].response.statusCode)
.eql(204);
await t
.expect(logger.requests[1].response.statusCode)
.eql(200);
});
While the first test works just fine, the second one, even if it's the same, will output an empty array once I'll try to console.log(logger.requests)
Any idea how to go about it?
I had the same problem because you have to wait for the Smart Assertion Query Mechanism of Testcafe before doing assertions on Logger.request array.
The documentation tells us that using count or contains predicates make Testcafe use the Smart Assertion Query mechanism
Suggestion from Marion may do the job if your request returns a 200 statusCode :
await t.expect(logger.contains(record => record.response.statusCode === 200)).ok();
I found simpler to do this instead, which does not depend on the returned http status
await t.expect(logger.count(() => true)).eql(1);
replace eql(1) with the number of requests you expect to be logged before doing your assertions
I have an unconventional setup I can't change. It looks something like this:
test POSTs to server
server POSTs to blockchain
blockchain updates
syncing script updates the database
It is absolutely imperative that I do not run the next test until the test before it has completed that entire workflow, which typically takes 2-3 seconds. Here is an example of a test written for that flow with supertest and chai:
it('should create a user', done => {
request(server)
.post(`${API}/signup`)
.set('Content-Type', 'application/json')
.send(`{
"email":"${USER_EMAIL}",
"password":"${USER_PASSWORD}"
}`)
.expect(200)
.expect(res => {
expect(res.body.role).to.equal('user');
expect(res.body.id).to.match(ID_PATTERN);
})
.end(_wait(done));
});
That _wait function is the key issue here. If I write it very naively with a setTimeout, it will work:
const _wait = cb => () => setTimeout(cb, 5000);
However, this isn't a great solution since the blockchain is very unpredictable, and can sometimes take much more than 2-3 seconds. What would be much better is to watch the database for changes. Thankfully the database is written in Rethink, which provides cursor objects that update on a change. So that should be easy, and look something like this:
var _wait = cb => () => {
connector.exec(db => db.table('chain_info').changes())
.then(cursor => {
cursor.each((err, change) => {
cb(err);
return false;
});
});
};
This setup breaks the tests. As near as I can tell done does get called. Any console logs in and around it fire, and the test itself is logged as completed, but the next test never starts, and eventually everything times out:
Manager API Workflow:
Account Creation:
✓ should create a user (6335ms)
1) should login an administrator
1 passing (1m)
1 failing
1) Manager API Workflow: Account Creation: should login an administrator:
Error: timeout of 60000ms exceeded. Ensure the done() callback is being called in this test.
Any assistance would be greatly appreciated. I am using Mocha 3.1.2, Chai 3.5.0, Supertest 2.0.1, and Node 6.9.1.