Hi! I am making some tests using mocha and chai for the app that I am building using next-auth.
I have to make some tests for the API, as anon and as a logged user.
The method we are using is by sending the log-in token.
I would love to know how to get the log-in token so i can test my API as different users.
Is there any examples of how to test it properly?
Hi! Hmm not right now, sorry - but there should be and I appreciate the request.
Will look into it and rustle up some tests.
Hi Ian! Thanks for your reply
So I was able to make tests on mocha, chai using the chai-http pluggin and using an agent to store the cookie and getting a crsfToken.
According to the core code, you have an AJAX response available if functions.signIn is available.
/*
* Enable /auth/signin routes if signIn() function is passed
*/
if (functions.signIn) {
expressApp.post(`${pathPrefix}/signin`, (req, res) => {
// Passes all supplied credentials to the signIn function
functions.signIn({
form: req.body,
req: req
})
.then(user => {
if (user) {
// If signIn() returns a user, sign in as them
req.logIn(user, (err) => {
if (err) return res.redirect(`${pathPrefix}/error?action=signin&type=credentials`)
if (req.xhr) {
// If AJAX request (from client with JS), return JSON response
return res.json({success: true})
} else {
// If normal form POST (from client without JS) return redirect
return res.redirect(`${pathPrefix}/callback?action=signin&service=credentials`)
}
})
} else {
// If no user object is returned, bounce back to the sign in page
return res.redirect(`${pathPrefix}`)
}
})
.catch(err => {
return res.redirect(`${pathPrefix}/error?action=signin&type=credentials`)
})
})
}
(there is also AJAX response for functions.sendSignInEmail but I think you still have make a GET to the url with the token to login).
In our app, we don't have signIn available in prod, but I decided to make it available for testing purposes,
signIn: async ({ form, req }) => {
return new Promise((resolve, reject) => {
if (process.env.NODE_ENV === 'test') {
// log.debug('TEST env - SignIn available')
return User.get({ email: form.email })
.then((user) => {
// console.log('User: ' + user)
if (!user) return resolve(null)
return resolve(user)
})
} else {
log.error('No TEST env. SignIn method not allowed')
return reject(new Error('Not allowed'))
}
})
}
So In my mocha - chai - chai-http test I did this:
let newUser1 = null
let csrfToken = null
let newAdmin = null
let agent = null
describe('/api/v1.0/users', () => {
before(async () => {
await require('../../../main')
await User.remove({})
newUser1 = await (new User(sampleUser1)).save()
newAdmin = await (new User(sampleAdmin)).save()
})
describe('As Logged user', () => {
before(async () => {
// Log In as aser
agent = await chai.request.agent('http://localhost:3000')
})
it('should get csrfToken', async () => {
await agent.get('/auth/csrf')
.then((res) => {
expect(res).to.have.status(OK)
expect(res.body).to.be.a('object')
expect(res.body).to.have.property('csrfToken')
csrfToken = res.body.csrfToken
})
.catch((err) => {
throw err
})
})
it('should log in', async () => {
await agent.post('/auth/signin')
.set('X-CSRF-TOKEN', csrfToken)
.set('X-Requested-With', 'XMLHttpRequest')
.set('Content-Type', 'application/x-www-form-urlencoded')
.send({ email: newUser1.email })
.then((res) => {
expect(res).to.have.status(OK)
expect(res).to.have.header('content-type', 'application/json; charset=utf-8')
expect(res.body).to.be.a('object')
expect(res.body).to.have.property('success')
expect(res.body.success).to.be.equal(true)
})
.catch((err) => {
throw err
})
})
it('the session should have a user object', async () => {
await agent.get('/auth/session')
.set('X-CSRF-TOKEN', csrfToken)
.set('X-Requested-With', 'XMLHttpRequest')
.set('Content-Type', 'application/x-www-form-urlencoded')
.then((res) => {
expect(res).to.have.status(OK)
expect(res).to.have.header('content-type', 'application/json; charset=utf-8')
expect(res.body).to.be.a('object')
expect(res.body.user).to.be.a('object')
expect(res.body.user).to.have.property('name')
})
.catch((err) => {
throw err
})
})
})
So yeah.. all i do then is making new tests using the same agent and the correct headers to send the csrfToken (cause if not, i get a 403 FORBIDDEN because of csrf token misssing or mismatch). Then, if i want to switch user I just drop the agent and make a new one.
I guess it would be nice to implement JSON responses, like the one you send when req.xhr is available (an AJAX request), for testing purposes maybe. {'success': true} is OK, but if it fails I would like an JSON response too, maybe some other data attached to the success == true event would be awesome too, like the user who just signed in. And also, AJAX responses available for /logout too, for example, would be awesome
Sorry I haven't had time to look at it earlier, thanks for this - it's very useful!
(I'll try and provide a more useful update soon. :-)
Hey! @mayankparihar1988
Yeah, set( ) should set a header in your POST request.
I dont know why its not working.. try to use this ones:
.set('X-CSRF-TOKEN', retrivedToken)
.set('X-Requested-With', 'XMLHttpRequest')
Hi @guillecro thanks, Its correct way to send X-CSRF-TOKEN using
.set('X-CSRF-TOKEN', retrivedToken)
.set('X-Requested-With', 'XMLHttpRequest')
In Header some time we also need to send cookies along with X-XSRF_TOKEN. (Depend on the backend in my case SAP HANA required cookies along with X-CSRF-TOKEN)
.set('X-CSRF-TOKEN', retrivedToken)
.set('X-Requested-With', 'XMLHttpRequest') // No Requried but ok to send.
.set('Cookie', cookiesToSend)
Then it worked for me!
Thanks/Cheers,
Mayank
Thanks for these. Ugh, I can't believe I've ignored automating the testing this long. Embarrassing.
On it.
Most helpful comment
Hi Ian! Thanks for your reply
So I was able to make tests on mocha, chai using the chai-http pluggin and using an
agentto store the cookie and getting acrsfToken.According to the core code, you have an AJAX response available if
functions.signInis available.(there is also AJAX response for
functions.sendSignInEmailbut I think you still have make a GET to the url with the token to login).In our app, we don't have signIn available in prod, but I decided to make it available for testing purposes,
So In my mocha - chai - chai-http test I did this:
So yeah.. all i do then is making new tests using the same agent and the correct headers to send the csrfToken (cause if not, i get a 403 FORBIDDEN because of csrf token misssing or mismatch). Then, if i want to switch user I just drop the agent and make a new one.
I guess it would be nice to implement JSON responses, like the one you send when
req.xhris available (an AJAX request), for testing purposes maybe.{'success': true}is OK, but if it fails I would like an JSON response too, maybe some other data attached to the success == true event would be awesome too, like the user who just signed in. And also, AJAX responses available for/logouttoo, for example, would be awesome