jest testing pass variable to another test - javascript

I'm trying to assign a variable from one test to be accessed within another test. For example:
let user;
test('create new user', async () => {
const response = await createUser()
user = response
})
test('delete user', async () => {
const response = await deleteUser(user.id)
})
I understand that jest has a --runInBand option, however this still has user as undefined in "delete user". Any ideas how to accomplish this with jest? Thank you

Each test runs independently, and for good reason. Tests should be confirming isolated conditions, methods, and logic. All --runInBand does is run the tests in serially, but they still won't necessarily be able to share data objects the way you seem to be expecting.
Also, assuming these methods defer to a backend service of some kind, you're not going to easily be able to fully test the behavior of that system. It sounds like you want an end-to-end or integration testing framework, as opposed to a unit testing framework like Jest.
Keeping with Jest, you're likely going to need to mock whatever backend service is being called in createUser and deleteUser. Jest mocks can help replace external functions with new ones that create the types of conditions you want to test.
Alternatively or in addition, you might be able to stub your user object using beforeAll or beforeEach, creating sample data that allows you to test how deleteUser behaves when it's passed a particular object (likely bypassing whatever backend persistence with an aforementioned mock).

Related

How to manage data for the tests?

I have only one account - admin by default. I need to change user permissions to non-admin one. I believe that I have few options available (not great yet can be used)
Create a new endpoint on a server just for testing - to make it possible for non-admin user to update those permissions. This idea seems pretty odd to me to change something like that.
Have multiple users to be able to switch between them for different roles (all in all not that simple for now).
Connect to db within tests and make those changes on db - probably easiest option
Is it OK to create new endpoints for testing e.g. /publish-cypress? Is it OK to populate the database just for tests by running some operations on db?
On my personal opinion you shouldn't create testing endpoint.
What you should be testing is the method that will be called by these routes (Your service), and for front-end you can 'fake' these call to the api.
The simplest way to do that is to use something similar ton interfaces (you might want to look at typescript ;) )
An example to fake these calls in your tests:
I'll go with typescript as it'll be mush easier to understand (less code)
//here you define all calls possible to your api
//dont forget to always pass the gateway by reference so that you can change whenever you want between fake & real
interface MyGateway {
changeUserPermission(userId, permissions);
}
//here do the actual implementation that will be used by your app
class MyApiGateway implements MyGateway {
public changeUserPermission(userId, permissions) {
//here is your real api call with fetch, axios or whatever
fetch('http://example.com/perms')...
}
}
//now you can do another implementation for testing purposes
class MyTestGateway implements MyGateway {
//here you can return hard values or do whatever you want so that your app doesn't depends on you backend
public changeUserPermission(userId, permissions) {
console.log(`Updating ${userId} is ${permissions}`);
}
}

Outputing Logs in Reporter Cypress

I am writing a test kit on cypress for my web application. One thing I want to be able to do is display certain data about the state of the application appended to each test so I know the particulars of that user's configuration. For example, the url of the test, whether the user has certain permissions or not etc. I am using mochawesome for the reporting but am not entirely partial to it. Is there some way to add data that comes from cy.get, cy.find... commands to the reporting?
I figured it out. Add this to support/commands.js
import addContext from 'mochawesome/addContext';
Cypress.Commands.add('addContext', (context) => {
cy.once('test:after:run', (test) => addContext({ test }, context));
});
Then use the function through cy.addContext("whatever").
It will get added to the mochawesome test file.

When using Jasmine's exceptGET / $httpBackend, what's the benefit of having .respond()?

I am using the book called AngularJS Up and Running. It gives an example of using exceptGET. This is the example:
mockBackend = $httpBackend;
mockBackend.exceptGET('/api/note')
.respond([{id:1, label: 'Mock'}]);
My question is, isn't the point of unittesting server calls to make the server call and verify that the server call is what we expect it to be?
With the above code, does it not just make a server call and force the response to equal [{id:1, label: 'Mock'}]? What's the point of doing it if we aren't able to check what the actual response is?
Because later on in the code, it checks the response like so:
mockBackend.flush();
expect(ctrl.items).toEqual([{id:1, label: 'Mock'}]);
Wouldn't it Always equal [{id:1, label: 'Mock'}] because that's what we forced the response to equal? What's the benefit of having .respond() and controlling the response?
If you would actually hit an API endpoint on the server in your unit test, it would not be a unit test anymore - it would now involve much more than just your component under test (controller/service/provider etc) - the network, the web server, the backend itself, probably a database etc - now this becomes an integration test or a system/functional test.
Your unit test would not be isolated anymore and would depend on more things than it should. The point of mocking is to make the test isolated, independent and imitate certain desired conditions - in this case an HTTP response - and then check how your component under test would react.
expect(ctrl.items).toEqual([{id:1, label: 'Mock'}]);
This expect call itself, at least, would check that the mock was successfully applied and the items controller variable contains the mocked response.
Please see more at:
Unit tests vs Functional tests
What is Mocking?

How to keep protractor running?

I'm trying to access Db in protractor tests using a sql server driver for NodeJs (protractor is a nodejs application so this is no problem)
The idea is to check Db data in our e2e tests:
We can check whether some hidden things are written correctly in the Db that cannot be seen on the UI (e.x Logs,..)
We can isolate features in our e2e testing: we don't rely on another feature to display the data to check whether the feature writing the data works correctly.
The problem I'm having is whenever protractor finishes interacting with the browser, it will terminate. Therefore, my code to access the Db cannot verify the data retrieved (e.x expect(dataFromDb).toEqual('foo')) because requests to Db are asynchronous in NodeJs.
At the time when I retrieve the data via the callback, protractor has been terminated.
It looks to me that protractor is only aware of web browser promises and terminates when there are no outstanding browser promises.
Is there any solution to keeping protractor alive so that I can verify my Db data? Thanks.
Two things to keep in mind.
1) expect(dataFromDb).toEqual('foo')): Protractor wrapped expect to understand promises. However, it only understands webdriver.promise (i.e. no $q or any other promise). If you want to make assertions against non webdriver promises, you have to resolve the promise yourself like:
dataFromDb.then(function(resolvedData) {
expect(resolvedData).toEqual('foo')
})
2) Protractor does not "terminate". Protractor only helps you kick off your test using another test framework (i.e. jasmine, mocha); once it does that it is only a library of tools (i.e. locators, waitForAngular, etc) that you run on top of that test framework. It's that other framework you must prevent from terminating. I don't know what framework you're using, but I'll use jasmine as an example:
it('call db', function(done) { //notice the inclusion of `done`
browser.get('something'); //this is protractor
element(by.xyz).click(); //this is protractor
var data = queryDatabase(); // you must tell jasmine to wait for this.
data.then(function(resolvedData) {
expect(resolvedData).toBe('foo');
done(); // tell jasmine you're done.
})
})
Side note, protractor patched jasmine it to wait for webdriver commands to finish (just like how it patched expect) for user's convenience. However, if you don't use webdriver's promise you need to tell it when the test is done via the done callback

Configuring Intern to setup/teardown my server mock

I am writing a test suite for a JavaScript widget using Intern.
I have written some pure-JavaScript tests and some in-page DOM tests, but I'm a little stuck on how to write functional tests for the Ajax functionality, which should talk to my simple Node.js mock server (which works a treat for manual tests).
Specifically, what I would like to do:
Start the Node.js mock server as part of the test suite's setup phase
Teardown the mock server when the test is over
(Bonus points) Be able to interrogate the mock server from my Intern tests, for example, checking on the contents of a POST request to the mock
I am stuck on all three - I can't find any documentation or example code from Intern on how to handle setup or teardown of a separate process (like a Node.js mock server) in the test suite.
I am using Intern with Sauce Labs (hosted Selenium) - I'm not sure if my problem needs to be solved on just the Intern side, or on the Sauce Labs side as well. Hopefully somebody has got this working and can advise.
If you want a server to start and stop for each suite, the setup and teardown methods would be the place to do this, something like:
var server;
registerSuite({
name: 'myTests',
setup: function () {
server = startServer();
},
teardown: function () {
server.close();
},
...
});
startServer would be whatever function you use to start your test server. Presumably it would return an object that would be used to interact with the server. Any tests within the suite would then have access to the server object.

Categories

Resources