Merge pull request #14530 from overleaf/jpa-check-response-status

[web] check response status code in acceptance tests

GitOrigin-RevId: 119a13f03bb3f1e8bb39340c36a9f2b0649b2bba
This commit is contained in:
Jakob Ackermann 2023-08-28 13:58:27 +02:00 committed by Copybot
parent 63bd1f6095
commit 1ae5c2c2f1
8 changed files with 260 additions and 64 deletions

View file

@ -1,3 +1,4 @@
const OError = require('@overleaf/o-error')
const { expect } = require('chai')
const async = require('async')
const User = require('./helpers/User')
@ -22,9 +23,15 @@ describe('AdminEmails', function () {
it('should block the user', function (done) {
this.badUser.login(err => {
expect(err).to.not.exist
// User.login refreshes the csrf token after login.
// Seeing the csrf token request fail "after login" indicates a successful login.
expect(OError.getFullStack(err)).to.match(/TaggedError: after login/)
expect(OError.getFullStack(err)).to.match(
/get csrf token failed: status=500 /
)
this.badUser.getProjectListPage((err, statusCode) => {
expect(err).to.exist
expect(err).to.not.exist
expect(statusCode).to.equal(500)
done()
})
})

View file

@ -27,11 +27,14 @@ describe('AdminOnlyLogin', function () {
}
async function expectRejectedLogin(user) {
const response = await user.login()
expect(response.statusCode).to.equal(403)
expect(response.body).to.deep.equal({
message: { type: 'error', text: 'Admin only panel' },
})
try {
await user.login()
expect.fail('expected the login request to fail')
} catch (err) {
expect(err).to.match(
/login failed: status=403 body={"message":{"type":"error","text":"Admin only panel"}}/
)
}
}
describe('adminOnlyLogin=true', function () {

View file

@ -162,7 +162,14 @@ describe('HaveIBeenPwnedApi', function () {
}
})
beforeEach('login', async function () {
try {
await user.loginWithEmailPassword(user.email, 'aLeakedPassword42')
expect.fail('expected the login request to fail')
} catch (err) {
expect(err).to.match(
/login failed: status=401 body={"message":{"text":"Your email or password is incorrect. Please try again.","type":"error"}}/
)
}
await letPasswordCheckRunInBackground()
})
it('should not increment any counter', async function () {

View file

@ -98,7 +98,7 @@ describe('Project ownership transfer', function () {
this.projectId,
this.collaborator._id
)
).to.be.rejectedWith('Unexpected status code: 403')
).to.be.rejectedWith(/failed: status=403 /)
})
it('prevents transfers to a non-collaborator', async function () {
@ -107,7 +107,7 @@ describe('Project ownership transfer', function () {
this.projectId,
this.stranger._id
)
).to.be.rejectedWith('Unexpected status code: 403')
).to.be.rejectedWith(/failed: status=403 /)
})
it('allows an admin to transfer to any project to a non-collaborator', async function () {

View file

@ -360,7 +360,9 @@ describe('Registration', function () {
this.user1.addEmail(secondaryEmail, err => {
expect(err).to.not.exist
this.user1.loginWith(secondaryEmail, err => {
expect(err != null).to.equal(false)
expect(err).to.match(
/login failed: status=401 body={"message":{"text":"Your email or password is incorrect. Please try again.","type":"error"}}/
)
this.user1.isLoggedIn((err, isLoggedIn) => {
expect(err).to.not.exist
expect(isLoggedIn).to.equal(false)

View file

@ -53,7 +53,7 @@ describe('Sharing', function () {
this.collaborator._id,
{ privilegeLevel: 'readAndWrite' }
)
).to.be.rejectedWith('Unexpected status code: 403')
).to.be.rejectedWith(/failed: status=403 /)
})
it('validates the privilege level', async function () {
@ -63,7 +63,7 @@ describe('Sharing', function () {
this.collaborator._id,
{ privilegeLevel: 'superpowers' }
)
).to.be.rejectedWith('Unexpected status code: 400')
).to.be.rejectedWith(/failed: status=400 /)
})
it('returns 404 if the user is not already a collaborator', async function () {
@ -73,7 +73,7 @@ describe('Sharing', function () {
this.stranger._id,
{ privilegeLevel: 'readOnly' }
)
).to.be.rejectedWith('Unexpected status code: 404')
).to.be.rejectedWith(/failed: status=404 /)
})
})

View file

@ -1,3 +1,4 @@
const OError = require('@overleaf/o-error')
const request = require('./request')
const settings = require('@overleaf/settings')
const { db, ObjectId } = require('../../../../app/src/infrastructure/mongodb')
@ -96,6 +97,15 @@ class User {
if (error != null) {
return callback(error)
}
if (response.statusCode !== 200) {
return callback(
new Error(
`register failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
db.users.findOne({ email: this.email }, (error, user) => {
if (error != null) {
return callback(error)
@ -143,10 +153,19 @@ class User {
if (error != null) {
return callback(error)
}
if (response.statusCode !== 200) {
return callback(
new Error(
`login failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
// get new csrf token, then return result of login
this.getCsrfToken(err => {
if (err) {
return callback(err)
return callback(OError.tag(err, 'after login'))
}
callback(null, response, body)
})
@ -226,6 +245,15 @@ class User {
if (error != null) {
return callback(error)
}
if (response.statusCode !== 200) {
return callback(
new Error(
`logout failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
db.users.findOne({ email: this.email }, (error, user) => {
if (error != null) {
return callback(error)
@ -344,16 +372,19 @@ class User {
url: '/user/delete',
json: { password: this.password },
},
(err, res) => {
(err, response, body) => {
if (err) {
return callback(err)
}
if (res.statusCode < 200 || res.statusCode >= 300) {
if (response.statusCode !== 200) {
return callback(
new Error('Error received from API: ' + res.statusCode)
new Error(
`user deletion failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
callback()
}
)
@ -383,6 +414,15 @@ class User {
if (error != null) {
return callback(error)
}
if (response.statusCode !== 200) {
return callback(
new Error(
`project creation failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
if ((body != null ? body.project_id : undefined) == null) {
error = new Error(
JSON.stringify([
@ -411,6 +451,15 @@ class User {
if (error != null) {
return callback(error)
}
if (response.statusCode !== 200) {
return callback(
new Error(
`project deletion failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
callback(null)
}
)
@ -421,14 +470,16 @@ class User {
{
url: `/admin/project/${projectId}/undelete`,
},
(error, response) => {
(error, response, body) => {
if (error) {
return callback(error)
}
if (response.statusCode !== 204) {
return callback(
new Error(
`Non-success response when undeleting project: ${response.statusCode}`
`project un-deletion failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
@ -451,10 +502,13 @@ class User {
return callback(error)
}
if (response.statusCode !== 200) {
const err = new Error(
`Non-success response when opening project: ${response.statusCode}`
return callback(
new Error(
`opening project failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
return callback(err)
}
callback(null)
}
@ -478,6 +532,15 @@ class User {
if (error != null) {
return callback(error)
}
if (response.statusCode !== 200) {
return callback(
new Error(
`doc creation in project failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
callback(null, body._id)
}
)
@ -506,12 +569,18 @@ class User {
},
},
},
(error, res, body) => {
(error, response, body) => {
if (error) {
return callback(error)
}
if (res.statusCode < 200 || res.statusCode >= 300) {
return callback(new Error(`failed to upload file ${res.statusCode}`))
if (response.statusCode !== 200) {
return callback(
new Error(
`uploading file failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
callback(null, JSON.parse(body).entity_id)
@ -538,12 +607,18 @@ class User {
folder_id: folderId,
},
},
(error, res) => {
(error, response, body) => {
if (error) {
return callback(error)
}
if (res.statusCode < 200 || res.statusCode >= 300) {
return callback(new Error(`failed to move ${type} ${res.statusCode}`))
if (response.statusCode !== 200) {
return callback(
new Error(
`move item in project failed: type=${type} status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
callback()
@ -559,13 +634,17 @@ class User {
name,
},
},
(error, res) => {
(error, response, body) => {
if (error) {
return callback(error)
}
if (res.statusCode < 200 || res.statusCode >= 300) {
if (response.statusCode !== 204) {
return callback(
new Error(`failed to rename ${type} ${res.statusCode}`)
new Error(
`rename item in project failed: type=${type} status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
@ -577,13 +656,17 @@ class User {
deleteItemInProject(projectId, type, itemId, callback) {
this.request.delete(
`project/${projectId}/${type}/${itemId}`,
(error, res) => {
(error, response, body) => {
if (error) {
return callback(error)
}
if (res.statusCode < 200 || res.statusCode >= 300) {
if (response.statusCode !== 204) {
return callback(
new Error(`failed to delete ${type} ${res.statusCode}`)
new Error(
`delete item in project failed: type=${type} status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
callback()
@ -604,13 +687,17 @@ class User {
json: true,
jar: false,
},
(error, res, body) => {
(error, response, body) => {
if (error) {
return callback(error)
}
if (res.statusCode < 200 || res.statusCode >= 300) {
if (response.statusCode !== 200) {
return callback(
new Error(`failed to join project ${projectId} ${res.statusCode}`)
new Error(
`join project failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
callback(null, body)
@ -651,6 +738,15 @@ class User {
if (error != null) {
return callback(error)
}
if (response.statusCode !== 204) {
return callback(
new Error(
`disable link sharing failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
callback(null)
}
)
@ -668,6 +764,15 @@ class User {
if (error != null) {
return callback(error)
}
if (response.statusCode !== 204) {
return callback(
new Error(
`enable link sharing failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
callback(null)
}
)
@ -682,6 +787,15 @@ class User {
if (err != null) {
return callback(err)
}
if (response.statusCode !== 200) {
return callback(
new Error(
`get csrf token failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
this.csrfToken = body
this.request = this.request.defaults({
headers: {
@ -707,10 +821,19 @@ class User {
newPassword2: newPassword,
},
},
err => {
(err, response, body) => {
if (err) {
return callback(err)
}
if (response.statusCode !== 200) {
return callback(
new Error(
`change password failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
this.password = newPassword
callback()
}
@ -730,7 +853,7 @@ class User {
email: userEmail,
},
},
(error, response, body) => {
(error, response) => {
callback(error, response)
}
)
@ -750,6 +873,15 @@ class User {
if (error != null) {
return callback(error)
}
if (response.statusCode !== 200) {
return callback(
new Error(
`open settings page failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
callback(null, response.statusCode)
}
)
@ -766,27 +898,29 @@ class User {
url: '/user/settings',
json: newSettings,
},
callback
(err, response, body) => {
if (err) return callback(err)
if (response.statusCode !== 200) {
return callback(
new Error(
`login failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
callback()
}
)
})
}
getProjectListPage(callback) {
this.getCsrfToken(error => {
if (error != null) {
return callback(error)
}
this.request.get(
{
url: '/project',
},
(error, response, body) => {
this.request.get('/project', (error, response) => {
if (error != null) {
return callback(error)
}
callback(null, response.statusCode)
}
)
})
}
@ -802,7 +936,7 @@ class User {
} else {
callback(
new Error(
`unexpected status code from /user/personal_info: ${response.statusCode}`
`unexpected status code from /user/personal_info: status=${response.statusCode} body=${body}`
)
)
}
@ -821,13 +955,17 @@ class User {
user_id: userId.toString(),
},
},
(err, response) => {
(err, response, body) => {
if (err != null) {
return callback(err)
}
if (response.statusCode !== 204) {
return callback(
new Error(`Unexpected status code: ${response.statusCode}`)
new Error(
`transfer project ownership failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
callback()
@ -860,13 +998,17 @@ class User {
url: `/project/${projectId.toString()}/users/${userId.toString()}`,
json: info,
},
(err, response) => {
(err, response, body) => {
if (err != null) {
return callback(err)
}
if (response.statusCode !== 204) {
return callback(
new Error(`Unexpected status code: ${response.statusCode}`)
new Error(
`update collaborator access failed: status=${
response.statusCode
} body=${JSON.stringify(body)}`
)
)
}
callback()

View file

@ -1,4 +1,3 @@
const { expect } = require('chai')
const { CookieJar } = require('tough-cookie')
const AuthenticationManager = require('../../../../app/src/Features/Authentication/AuthenticationManager')
const Settings = require('@overleaf/settings')
@ -120,7 +119,15 @@ class UserHelper {
async getCsrfToken() {
// get csrf token from api and store
const response = await this.fetch('/dev/csrf')
this._csrfToken = await response.text()
const body = await response.text()
if (response.status !== 200) {
throw new Error(
`get csrf token failed: status=${response.status} body=${JSON.stringify(
body
)}`
)
}
this._csrfToken = body
}
/**
@ -307,6 +314,13 @@ class UserHelper {
...options,
})
const body = await response.json()
if (response.status !== 200) {
throw new Error(
`register failed: status=${response.status} body=${JSON.stringify(
body
)}`
)
}
if (body.message && body.message.type === 'error') {
throw new Error(`register api error: ${body.message.text}`)
}
@ -338,7 +352,14 @@ class UserHelper {
method: 'POST',
body: new URLSearchParams([['email', email]]),
})
expect(response.status).to.equal(204)
const body = await response.text()
if (response.status !== 204) {
throw new Error(
`add email failed: status=${response.status} body=${JSON.stringify(
body
)}`
)
}
}
async addEmailAndConfirm(userId, email) {
@ -408,7 +429,14 @@ class UserHelper {
method: 'POST',
body: new URLSearchParams([['email', email]]),
})
expect(response.status).to.equal(200)
if (response.status !== 200) {
const body = await response.text()
throw new Error(
`resend confirmation failed: status=${
response.status
} body=${JSON.stringify(body)}`
)
}
const tokenData = await db.tokens
.find({
use: 'email_confirmation',
@ -421,7 +449,14 @@ class UserHelper {
method: 'POST',
body: new URLSearchParams([['token', tokenData.token]]),
})
expect(response.status).to.equal(200)
if (response.status !== 200) {
const body = await response.text()
throw new Error(
`confirm email failed: status=${response.status} body=${JSON.stringify(
body
)}`
)
}
}
}