Skip to content

Commit 04b8b02

Browse files
committed
Added integration and unit tests for the feature flag
1 parent afa0b94 commit 04b8b02

File tree

8 files changed

+330
-15
lines changed

8 files changed

+330
-15
lines changed

controllers/featureFlags.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ const featureFlagQuery = require('../models/featureFlags')
1010
const getFeatureFlags = async (req, res) => {
1111
try {
1212
const allFeatureFlags = await featureFlagQuery.fetchFeatureFlag()
13+
// console.log(res.status);
1314
return res.json({
14-
message: 'All feature-flags returned successfully',
15+
message: 'FeatureFlags returned successfully!',
1516
featureflags: allFeatureFlags.length > 0 ? allFeatureFlags : []
1617
})
1718
} catch (err) {
@@ -31,8 +32,8 @@ const addFeatureFlag = async (req, res) => {
3132
try {
3233
const featureFlag = await featureFlagQuery.addFeatureFlags(req.body, req.userData.username)
3334
return res.json({
34-
message: 'FeatureFlag added successfully',
35-
featureFlag
35+
message: 'FeatureFlag added successfully!',
36+
data: featureFlag
3637
})
3738
} catch (err) {
3839
logger.error(`Error while adding featureFlag info: ${err}`)
@@ -51,7 +52,7 @@ const updateFeatureFlag = async (req, res) => {
5152
try {
5253
const result = await featureFlagQuery.updateFeatureFlags(req.body, req.params.id)
5354
if (result.isUpdated) {
54-
return res.json({ message: 'FeatureFlag updated successfully!' })
55+
return res.status(204).send()
5556
}
5657
return res.boom.notFound('FeatureFlag doesn\'t exist')
5758
} catch (err) {

middlewares/validators/featureFlags.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ const validateFeatureFlag = async (req, res, next) => {
66
title: joi.string().required(),
77
created_at: joi.number().optional(),
88
updated_at: joi.number().optional(),
9-
config: joi.object().required(),
9+
config: joi.object({
10+
enabled: joi.boolean().required()
11+
}).required(),
1012
launched_at: joi.number().optional()
1113
})
1214

@@ -22,7 +24,9 @@ const validateFeatureFlag = async (req, res, next) => {
2224
const updateFeatureFlags = async (req, res, next) => {
2325
const schema = joi.object().keys({
2426
title: joi.string().optional(),
25-
config: joi.object().required()
27+
config: joi.object({
28+
enabled: joi.boolean().required()
29+
}).required()
2630
})
2731
try {
2832
await schema.validateAsync(req.body)

models/featureFlags.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,14 @@ const fetchFeatureFlag = async () => {
2424
if (!users.includes(item.owner)) { users.push(item.owner) }
2525
})
2626

27-
const getImage = async (usersData) => {
28-
return await userModel.fetchUserImage(usersData)
29-
}
30-
3127
let start = 0
3228
let end = 10
3329

3430
for (let i = 0; i < Math.ceil(users.length / 10); i++) {
3531
const usersData = users.slice(start, end)
32+
const image = await userModel.fetchUserImage(usersData)
3633
start = end
3734
end += 10
38-
const image = await getImage(usersData)
3935
Object.assign(result, image)
4036
}
4137

@@ -120,6 +116,7 @@ const deleteFeatureFlag = async (featureFlagId) => {
120116
isDeleted: false
121117
}
122118
}
119+
await featureFlagModel.doc(featureFlagId).delete()
123120
return {
124121
isDeleted: true
125122
}

models/users.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,11 @@ const updateUserPicture = async (image, userId) => {
174174
*/
175175
const fetchUserImage = async (users) => {
176176
const data = await userModel.where('username', 'in', users).get()
177-
const hash = {}
177+
const images = {}
178178
data.forEach((item) => {
179-
hash[item.data().username] = item.data().img
179+
images[item.data().username] = item.data().img
180180
})
181-
// console.log(hash)
182-
return hash
181+
return images
183182
}
184183

185184
module.exports = {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module.exports = () => {
2+
return [
3+
{
4+
name: 'Test-feature',
5+
title: 'Test',
6+
config: {
7+
enabled: true
8+
}
9+
}
10+
]
11+
}

test/fixtures/user/user.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,26 @@ module.exports = () => {
9292
roles: {
9393
super_user: true
9494
}
95+
},
96+
{
97+
username: 'ankita',
98+
first_name: 'Ankita',
99+
last_name: 'Bannore',
100+
yoe: 0,
101+
img: './img.png',
102+
linkedin_id: 'ankitabannore',
103+
github_id: 'Ankita2002-Fr',
104+
github_display_name: 'Ankita Bannore',
105+
isMember: true,
106+
phone: '1234567890',
107+
108+
tokens: {
109+
githubAccessToken: 'githubAccessToken'
110+
},
111+
status: 'active',
112+
roles: {
113+
app_owner: true
114+
}
95115
}
96116
]
97117
}
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
const chai = require('chai')
2+
const { expect } = require('chai')
3+
const chaiHttp = require('chai-http')
4+
5+
const app = require('../../server')
6+
const authService = require('../../services/authService')
7+
const addUser = require('../utils/addUser')
8+
const cleanDb = require('../utils/cleanDb')
9+
const featureFlagQuery = require('../../models/featureFlags')
10+
11+
// Import fixtures
12+
const userData = require('../fixtures/user/user')()
13+
const featureFlagData = require('../fixtures/featureFlag/featureFlag')()
14+
15+
const config = require('config')
16+
const cookieName = config.get('userToken.cookieName')
17+
18+
const appOwner = userData[5]
19+
chai.use(chaiHttp)
20+
21+
describe('FeatureFlag', function () {
22+
let jwt
23+
let featureFlag
24+
beforeEach(async function () {
25+
const userId = await addUser(appOwner)
26+
jwt = authService.generateAuthToken({ userId })
27+
featureFlag = await featureFlagQuery.addFeatureFlags(featureFlagData[0], appOwner.username)
28+
})
29+
30+
afterEach(async function () {
31+
await cleanDb()
32+
})
33+
34+
describe('GET /featureFlags', function () {
35+
it('Should return all feature flags', function (done) {
36+
chai
37+
.request(app)
38+
.get('/featureFlags')
39+
.end((res, err) => {
40+
if (err) { return done() }
41+
42+
expect(res).to.have.status(200)
43+
expect(res.body).to.be.a('object')
44+
expect(res.body.message).to.equal('FeatureFlags returned successfully!')
45+
expect(res.body.featureFlags).to.be.a('array')
46+
47+
return done()
48+
})
49+
})
50+
})
51+
52+
describe('POST /featureFlags', function () {
53+
it('Should add the feature flag in db', function (done) {
54+
chai
55+
.request(app)
56+
.post('/featureFlags')
57+
.set('cookie', `${cookieName} = ${jwt}`)
58+
.send({
59+
name: 'test',
60+
title: 'test-feature',
61+
config: {
62+
enabled: true
63+
}
64+
}, appOwner.username)
65+
.end((err, res) => {
66+
if (err) { return done() }
67+
expect(res).to.have.status(200)
68+
expect(res.body).to.be.a('object')
69+
const { data } = res.body
70+
expect(data).to.be.a('object')
71+
expect(data.name).to.be.a('string')
72+
expect(data.title).to.be.a('string')
73+
expect(data.created_at).to.be.a('number')
74+
expect(data.updated_at).to.be.a('number')
75+
expect(data.config).to.be.a('object')
76+
expect(data.config.enabled).to.be.a('boolean')
77+
expect(data.owner).to.be.a('string')
78+
expect(res.body.message).to.equal('FeatureFlag added successfully!')
79+
80+
return done()
81+
})
82+
})
83+
84+
it('Should return 401 if user not logged in', function (done) {
85+
chai
86+
.request(app)
87+
.post('/featureFlags')
88+
.end((res, err) => {
89+
if (err) { return done() }
90+
91+
expect(res).to.have.status(401)
92+
expect(res.body).to.be.an('object')
93+
expect(res.body).to.eql({
94+
statusCode: 401,
95+
error: 'Unauthorized',
96+
message: 'Unauthenticated User'
97+
})
98+
99+
return done()
100+
})
101+
})
102+
})
103+
104+
describe('PATCH /featureFlags/:id', function () {
105+
it('Should update the feature flag', function (done) {
106+
chai
107+
.request(app)
108+
.patch(`/featureFlags/${featureFlag.id}`)
109+
.set('cookie', `${cookieName}=${jwt}`)
110+
.send({
111+
config: {
112+
enabled: false
113+
}
114+
})
115+
.end((err, res) => {
116+
if (err) { return done() }
117+
expect(res).to.have.status(204)
118+
119+
return done()
120+
})
121+
})
122+
123+
it('Should return 401 if user not logged in', function (done) {
124+
chai
125+
.request(app)
126+
.patch(`/featureFlags/${featureFlag.id}`)
127+
.end((res, err) => {
128+
if (err) { return done() }
129+
130+
expect(res).to.have.status(401)
131+
expect(res.body).to.be.an('object')
132+
expect(res.body).to.eql({
133+
statusCode: 401,
134+
error: 'Unauthorized',
135+
message: 'Unauthenticated User'
136+
})
137+
138+
return done()
139+
})
140+
})
141+
142+
it('Should return 404 if feature flag does not exist', function (done) {
143+
chai
144+
.request(app)
145+
.patch('/featureFlags/featureFlagId')
146+
.end((res, err) => {
147+
if (err) { return done() }
148+
149+
expect(res).to.have.status(404)
150+
expect(res.body).to.be.an('object')
151+
expect(res.body).to.eql({
152+
statusCode: 404,
153+
error: 'Not Found',
154+
message: 'No featureFlag found'
155+
})
156+
157+
return done()
158+
})
159+
})
160+
})
161+
162+
describe('DELETE /featureFlags/:id', function () {
163+
it('Should delete the feature flag', function (done) {
164+
chai
165+
.request(app)
166+
.delete(`/featureFlags/${featureFlag.id}`)
167+
.set('cookie', `${cookieName}=${jwt}`)
168+
.end((err, res) => {
169+
if (err) { return done() }
170+
171+
expect(res).to.have.status(200)
172+
173+
return done()
174+
})
175+
})
176+
177+
it('Should return 401 if user not logged in', function (done) {
178+
chai
179+
.request(app)
180+
.delete(`/featureFlags/${featureFlag.id}`)
181+
.end((res, err) => {
182+
if (err) { return done() }
183+
184+
expect(res).to.have.status(401)
185+
expect(res.body).to.be.an('object')
186+
expect(res.body).to.eql({
187+
statusCode: 401,
188+
error: 'Unauthorized',
189+
message: 'Unauthenticated User'
190+
})
191+
192+
return done()
193+
})
194+
})
195+
196+
it('Should return 404 if feature flag does not exist', function (done) {
197+
chai
198+
.request(app)
199+
.delete('/featureFlags/featureFlagId')
200+
.end((res, err) => {
201+
if (err) { return done() }
202+
203+
expect(res).to.have.status(404)
204+
expect(res.body).to.be.an('object')
205+
expect(res.body).to.eql({
206+
statusCode: 404,
207+
error: 'Not Found',
208+
message: 'No feature flag found'
209+
})
210+
211+
return done()
212+
})
213+
})
214+
})
215+
})

0 commit comments

Comments
 (0)