I'm new to cypress. My scenario is as follows:
1) Go to a test page.
2) Initiate an init script which interacts with the server and creates some session.
3) Go the backoffice
4) See that the new session appears in the table
The sessionId is received from the test page. When I initiate the session, I get the sessionId as a response (it is part of my test).
The problem is, that when I go to the backoffice (by using cy.visit) the whole cypress session resets, and I lose the sessionId.
I tried to use global variables and aliases, but to no avail.
Is there a way to pass the sessionId variable to the backoffice test?
Here's my code:
describe('Session init', () => {
let requestBody;
let responseBody;
let sessionId;
describe('Init the session in the client', () => {
before(() => {
cy.server();
cy.route({
method: 'POST',
url: initUrl,
onRequest: (xhr) => {
requestBody = xhr.request.body;
},
onResponse: (xhr) => {
responseBody = xhr.response.body;
}
}).as('init');
visitTestPage(); // uses cy.visit to go to the test page - also initiates a new session
});
it('should send POST init request', () => {
cy.wait('#init').then(() => {
expect(requestBody).to.contain.keys(
keysToExpectInRequest
);
});
});
it('should receive an init response', () => {
cy.wrap(responseBody.session).as('session');
sessionId = responseBody.session;
expect(responseBody).to.contain.keys(
keysToExpectInResponse
);
});
});
describe('Verify a session was created in backoffice', () => {
before(() => {
backofficeLogin(); // using cy.server and cy.visit, using premade jwt to avoid UI login
});
it('should see a live session with the id from the init', () => {
cy.get('.session-row').then((sessions) => {
expect(session[0].id).toEqual(sessionId); // expect the latest session created to be with the id of the session created in the test page
});
});
});
});
If you save the sessionId in the cookie you can use this:
cy.wrap(responseBody.session).as('session');
sessionId = responseBody.session;
cy.setCookie('sessionId', sessionId);
doc
But it is not recommended, because each test you perform must be independent of each other : doc
Related
I'm trying to test my fullstack angular-nestjs-application with cypress e2e tests.
Server calls from within angular to not reach my backend running on localhost:443 (I tested it with 0.0.0.0, 127.0.0.1 like some other answers requested - without success.
I also did try to add a local proxy on my machine like some other posts suggested - again without any success).
On the other hand: Requests sent by cy.request('http://localhost:443/...' do actually reach my backend. I am able to send the request in beforeEach, save the response, intercept the real request and feed the saved response data to it.
cy.login() does a login call to build a valid session for my backend.
describe('test', () => {
let data: any;
beforeEach(() => {
cy.login();
cy.request('http://localhost:443/load').then(response => {
data = response;
console.log('BeforeEach Response: ', data);
});
});
it('load data', () => {
cy.visit('/');
});
});
But the following line in beforeEach does work:
cy.request('http://localhost:443/load').then(response => {
data = response;
console.log('BeforeEach Response: ', data);
});
So the following test does work completely:
describe('test', () => {
let data: any;
beforeEach(() => {
cy.login();
cy.request('http://localhost:443/load').then(response => {
data = response;
console.log('BeforeEach Response: ', data);
});
});
it('load data', () => {
cy.intercept('/load', data);
cy.visit('/');
});
});
So what am i missing to successfully test my application with real server requests - without sending the same request by hand and stubing the real one?
I assume your baseUrl in cypress.json is not localhost:443. If that's the case, then for chrome-based browsers you can set chromeWebSecurity to false. See https://docs.cypress.io/guides/guides/web-security#Set-chromeWebSecurity-to-false.
If that doesn't help or you have to test with firefox then you have to put your app and all required backend-services behind a proxy, so that it looks like every request is served by the proxy.
If you have Angular in dev-mode then you already have a proxy and you can configure your backend services via proxy.conf.json. See https://angular.io/guide/build#proxying-to-a-backend-server
I am working on an application where I want to implement the message Inbox. I have created the message inbox using Angular8 and NodeJS REST API. Now I want to get the on inbox message in every 30 Second on the background when user login also it doesn't want to affecting the performance of the Angular app.
So I want to Implement the Web-worker with Angular8 to get the Data from NodeJS REST API but I am unable to create.
I have added following code in Angular 8 App
Add this code to app.component.ts
getWorker(token){
if (typeof Worker !== 'undefined') {
// Create a new
const worker = new Worker('../../web-worker/messenger.worker', { type: `module` });
worker.postMessage(token);
worker.onmessage = (e) => {
setTimeout(() => {
worker.postMessage(token)
}, 15000);
};
} else {
// Web Workers are not supported in this environment.
// You should add a fallback so that your program still executes correctly.
}
}
Created worker file with fetch
/// <reference lib="webworker" />
addEventListener('message', ({ data }) => {
const response = `worker response to ${data}`;
postMessage(response);
});
import { environment } from "src/environments/environment";
onmessage = (message:any) => {
fetch(environment.apiUrl +'messages/notification/1/1',
{ method:'GET',
headers:new Headers({
Authorization: `Bearer ${message.data}`
})
}
)
.then(response => {
return response.json()
})
.then(commits => {
// self.onmessage(message)
return commits
});
};
but it shows the type as fetch is should be show web worker Right?
Can anyone help me with this?
I'm using node and supertest for a simple app. I got SQlite3 for the local test database. I did a simple test to get a super inserted into the database. I wanted to reset the database each time a test is run. I'm looking in the docs right now and can't seem to locate it. I figured I would ask here because it seems someone would most likely know the info.
const request = require('supertest');
const server = require('../server');
describe('Authentication', function() {
//database reset here
it('should create a new user /users/registration', function(done) {
request(server)
.post('/users/register')
.send({
username: 'user-name',
email: 'luser-name#gmail.com',
password: '12345'
})
.set('Accept', 'application/json')
.expect(201, done);
});
});
If you want to run any piece of code before each test, you can use beforeEach function in jest
describe('my test', () => {
beforeEach(() => {
// code to run before each test
});
test('test 1', () => {
// code
});
test('test 2', () => {
// code
});
});
So best way to do this is have some logic in your routing functions of your Api
Receive an API request
Check if ['X-MOCK-HEADER'] exists
If it does then route to the mock version of the endpoint
So your mock for create user would always return 201 OK - your mock endpoint would do something like this:
const routes = {
CREATE_USER_OK:() => { return {....} } // make sure these return proper http responses
CREATE_USER_BAD_REQUEST: () { return {...} }
}
return routes[HEADER_VALUE]()
The reason being you're testing the route not the database class in this instance, so you just want to return static data, if you wanna test something else then just change the X-MOCK-HEADER value to whatever you want and add the mock route to return the right http response/code - I'd need to know what the API code looked like to help you on the backend implementation.
If possible stay away from messing with staging databases for testing because down the road you will suffer a LOT of pain as it gradually gets filled with garbage.
Also if you're working with a front end app you can quickly prototype with static data - this is especially useful if you've got a front end team waiting for an API endpoint to say create a login screen.
There's no defined way to reset a sqlite db, just delete the db and recreate.
Sqlite: How do I reset all database tables?
I did this in the file and it works fine
const request = require('supertest');
const server = require('../server');
const knex = require('knex');
const dbConfig = require('../knexfile.js')['test'];
const db = knex(dbConfig);
describe('Authentication', () => {
beforeEach(async () => {
await db('users').truncate();
});
it('should create a new user /users/registration', function(done) {
request(server)
.post('/users/register')
.send({
username: 'user-name',
email: 'luser-name#gmail.com',
password: '12345'
})
.set('Accept', 'application/json')
.expect(201, done);
});
});
Using Mocha/Chai for REST API unit testing, I need to be able to mock req.session.someKey for a few of the end points. How can I go about mocking req.session?
I'm working on writing REST API unit tests for a NodeJS Express app that utilizes express-session. Some of these endpoints require the use of data stored in req.session.someKey, the endpoint is setup to return a 400 if req.session.someKey is undefined so I need to be able to mock it in order for the test to complete successfully.
Example code:
router.get('/api/fileSystems', utilities.apiAuth, (req, res) => {
let customer = req.session.customer;
let route = (customer === 'NONE') ? undefined : customer;
if(route == undefined){
res.status(400).send('Can't have customer of undefined');
} else {
let requestOptions = setRequestOptions(route);
queryFileSystemInfo(requestOptions, (info) => {
res.status(200).send(info);
});
}
});
What I've tried:
describe('/GET /api/fileSystems', () => {
it('It should return information about the filesystem for a customer'), (done) => {
chai.request(server)
.get('api/fileSystems')
.set('customer', '146')
.end((err, res) => {
res.should.have.status(200);
done();
});
});
});
I attempted to use the .set() in order to set req.session but I believe that .set just sets the headers so I don't believe that I can update it that way unless I'm missing something.
In your express setup you usually plug in the session middleware like this
app.use(session(config))
instead you can put the session middleware in a handy accessible location, and make a wrapper for it, like this:
app.set('sessionMiddleware') = session(config)
app.use((...args) => app.get('sessionMiddleware')(...args)
Tests will need access to the express instance, you can do this by refactoring /app.js to export a function.
function app () {
const app = express()
// ... set up express
return app
}
// run app if module called from cli like `node app.js`
if (require.main === module) instance = app()
module.exports = app
Then in your test, you can overwrite app.sessionMiddleware
describe('/GET /api/fileSystems', () => {
it('It should return information about the filesystem for a customer'), (done) => {
app.set('sessionMiddleware') = (req, res, next) => {
req.session = mockSession // whatever you want here
next()
}
chai.request(server)
.get('api/fileSystems')
.set('customer', '146')
.end((err, res) => {
res.should.have.status(200);
done();
});
// then you can easily run assertions against your mock
chai.assert.equal(mockSession.value, value)
});
});
The other options I've seen on the net involve setting a cookie to match a session which is stored in the db, the problem with that approach is that you end up running into problems when the session in the db expires, so tests fail over time as fixtures become stale. With the approach outlined above you can work around that by setting expiries in the test.
mock-session is pretty use full to mock your session object
let mockSession = require('mock-session');
describe('/GET /api/fileSystems', () => {
it('It should return information about the filesystem for a customer'), (done) => {
let cookie = mockSession('my-session', 'my-secret', {"count":1}); // my-secret is you session secret key.
chai.request(server)
.get('api/fileSystems')
.set('cookie',[cookie])
.end((err, res) => {
res.should.have.status(200);
done();
});
});
});
For this project, I ended up having to set req.session.customer in our server.js file that has an app.use() call that uses a middleware function to set the current session. I was unable to actually find a package that directly mutates the req.session object at test time.
I'm using PhantomJS as follows to retrieve and parse data from a website.
const phantom = require('phantom');
const url = 'https://stackoverflow.com/'
let _ph, _page, _outObj;
phantom.create()
.then( (ph) => {
_ph = ph;
return _ph.createPage();
}).then( (page) => {
_page = page;
return page.open(url);
}).then( (status) => {
console.log(`Status: ${status}`);
return _page.property('content');
}).then( (data) => {
console.log(data);
_page.close();
_ph.exit();
}).catch( (e) => console.log(e));
What I need to do also is to store the cookie send by the server and include them in subsequent requests to the server - how do I go about it ?
PhantomJS is capable of storing and loading cookies by itself, according to docs there is a cli option for that:
--cookies-file=/path/to/cookies.txt specifies the file name to store the persistent Cookies
So with phantom node module you pass this option upon browser creation:
phantom.create(['--cookies-file=/path/to/cookies.txt']).then(...)