Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
4cc953f
add logout to unitsRouteTests.js
Nespina24 Jul 30, 2026
13206a2
add logout to usersTest.js and fix some formatting
Nespina24 Aug 3, 2026
badd17e
add logout to maps.js and revise some comments
Nespina24 Aug 3, 2026
5c3b0a5
create describe block for admin and add logout to preferencesTest.js
Nespina24 Aug 3, 2026
7b6d28a
add logout to meters.js and remove some blank lines
Nespina24 Aug 4, 2026
fa38778
change meters.js to use desired role, delete some comments
Nespina24 Aug 5, 2026
9a67537
Add logout after each test to logsRouteTests.js
Nespina24 Aug 5, 2026
db34c64
temporary fix to login/logout behavior
Nespina24 Aug 5, 2026
714b4fb
add logout to groups.js
Nespina24 Aug 6, 2026
6de5ae4
add logout to login.js tests
Nespina24 Aug 6, 2026
59fd32c
Merge branch 'OpenEnergyDashboard:development' into issue-1683-User-L…
Nespina24 Aug 26, 2026
9af5064
Merge branch 'OpenEnergyDashboard:development' into issue-1683-User-L…
Nespina24 Aug 27, 2026
a5fe6fd
Merge branch 'OpenEnergyDashboard:development' into issue-1683-User-L…
Nespina24 Sep 13, 2026
46c4796
Replace before/after hooks to beforeEach/afterEach hooks
Nespina24 Sep 13, 2026
191bab3
Separate admin and non-admin roles in create/edit endpoints
Nespina24 Sep 13, 2026
be817b6
Merge branch 'OpenEnergyDashboard:development' into issue-1683-User-L…
Nespina24 Sep 19, 2026
633824a
Merge branch 'OpenEnergyDashboard:development' into issue-1683-User-L…
Nespina24 Sep 26, 2026
c9a7715
fix indentation, const declarations, password strings
Nespina24 Sep 26, 2026
2e90d35
Merge branch 'OpenEnergyDashboard:development' into issue-1683-User-L…
Nespina24 Oct 3, 2026
d522f51
Merge branch 'OpenEnergyDashboard:development' into issue-1683-User-L…
Nespina24 Oct 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/server/test/routes/logsRouteTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ const { HTTP_CODES } = require('../../util/httpCodes');

mocha.describe('Log Routes', () => {
let token, currentLogToDb;

mocha.before(async () => {
// Login to get authentication token
const res = await chai.request(app).post('/api/loginLogout/login')
Expand All @@ -24,8 +23,12 @@ mocha.describe('Log Routes', () => {
currentLogToDb = log.logToDb;
log.logToDb = true;
});

mocha.after(async () => {

@Nespina24 Nespina24 Aug 11, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this test, I wanted to apply the potential change I noted in the issue description:

For tests with multiple users, instead of logging out all the users at the very end, it might be better to do one user at a time, log in, do the test & log out for each one.

Even though it doesn't have multiple users, I thought this would be a good place to login/logout for every test since it runs for a long time. However, when I tried changing to beforeEach/afterEach, the checks had continually failed.

I'm ok with leaving it like this, but I think this should be addressed if the root cause of the failures can be found.

@Nespina24 Nespina24 Aug 27, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm actually considering removing the changes to this file entirely. After implementing this, I've noticed that even though it passed the most recent test, the node checks have a chance of failing different tests for a reason I'm unaware of. If it gets merged, I'm afraid that other people will start seeing similar issues.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious. Do you want to wait until I review the PR to see if I have any ideas? One test should not, in a perfect world, impact another test. It makes me wonder if something else is wrong that really should be tracked down. If it cannot be tracked down during this work then I suspect a new issue should be opened to look at this further. Thoughts?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm okay with opening a new issue if it doesn't get resolved after a code review. If that's the case, then I think I should comment out the changes with a TODO describing the problem.

@huss huss Sep 9, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the tests in this file to use beforeEach/afterEach. I ran the single file of tests and the complete suite of tests multiple times but have yet to see it fail. Thus, I wanted to ask if you are still seeing this. If so, how often does it happen and is there anything special in your setup?

260921 update: This may be related to another comment on before/afterEach. I'm not adding any info but leaving it as part of that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for responding. I also don't see it on my local machine, but I was referring to the GitHub testing suite which seems to either successfully pass or give an error on different files, such as src/server/test/web/csvPipelineTest.js or src/server/test/routes/logsRouteTests.js even though it ran mostly the same code.

Recently it seems to be working on GitHub, but it could potentially be an issue if other people pull in these changes and it returns a phantom failure.

I'll change the code to beforeEach/afterEach for now and see if the problem persists.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made another comment about a potential issues I could not resolve. If this is not figured out soon then I propose to create an issue that documents the code you add (probably via a commit id) and discussed what is happening. Then it can be addressed later since there is a good chance it is not a direct result of this work. How does that sound?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me. I think I have a better understanding of what's happening now, but I agree that this could be a separate issue. I'm fine with creating an issue referencing the commit and including the debug output and any relevant information about the Mocha hook behavior.

// Logout after all tests are done
if (token) {
await chai.request(app).post('/api/loginLogout/logout')
.set('token', token);
}
// Reset after tests done.
log.logToDb = currentLogToDb;
});
Expand Down
12 changes: 10 additions & 2 deletions src/server/test/routes/unitsRouteTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,23 @@
const { mocha, expect, testDB, app, testUser } = require('../common');
const chai = require('chai');
const Unit = require('../../models/Unit');
const { HTTP_CODES } = require('../../util/httpCodes');

mocha.describe('Units Route', () => {
let token;

mocha.before(async () => {
// login
const res = await chai.request(app).post('/api/loginLogout/login')
.send({ username: testUser.username, password: testUser.password });
token = res.body.token;
});
mocha.after(async () => {
Comment thread
Nespina24 marked this conversation as resolved.
Outdated
// logout
if (token) {
await chai.request(app).post('/api/loginLogout/logout')
.set('token', token);
}
});

mocha.describe('Edit endpoint', () => {

Expand All @@ -28,7 +36,7 @@ mocha.describe('Units Route', () => {
name: 'New name',
identifier: unit.identifier,
});
expect(res).to.have.status(200);
expect(res).to.have.status(HTTP_CODES.OK);
const updatedUnit = await Unit.getById(unit.id, conn);
expect(updatedUnit.name).to.equal('New name');
expect(updatedUnit.note).to.equal(beforeNote);
Expand Down
19 changes: 19 additions & 0 deletions src/server/test/web/groups.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,19 @@ mocha.describe('groups API', () => {
// Since this .before is in the middle of tests, it should not have issues as
// documented in usersTest.js.
mocha.before(async () => {
// login
let res = await chai.request(app).post('/api/loginLogout/login')
.send({ username: testUser.username, password: testUser.password });
token = res.body.token;
});
mocha.after(async () => {
Comment thread
huss marked this conversation as resolved.
Outdated
// logout
if (token) {
await chai.request(app).post('/api/loginLogout/logout')
.set('token', token);
}
});

mocha.describe('create endpoint', () => {

mocha.it('rejects all requests with an invalid token with 401', async () => {
Expand Down Expand Up @@ -133,6 +142,11 @@ mocha.describe('groups API', () => {
// create
res = await chai.request(app).post('/api/groups/create').set('token', currentToken);
expect(res).to.have.status(expectedResponseStatus);
// logout
if (currentToken) {
await chai.request(app).post('/api/loginLogout/logout')
.set('token', currentToken);
}
});

}
Expand Down Expand Up @@ -190,6 +204,11 @@ mocha.describe('groups API', () => {
// edit
res = await chai.request(app).put('/api/groups/edit').set('token', currentToken);
expect(res).to.have.status(expectedResponseStatus);
// logout
if (currentToken) {
await chai.request(app).post('/api/loginLogout/logout')
.set('token', currentToken);
}
});

}
Expand Down
15 changes: 13 additions & 2 deletions src/server/test/web/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ mocha.describe('login API', () => {
expect(res).to.have.status(HTTP_CODES.OK);
expect(res).to.be.json;
expect(res.body).to.have.property('token');
let token = res.body.token;

if (token) {
Comment thread
huss marked this conversation as resolved.
await chai.request(app).post('/api/loginLogout/logout')
.set('token', token);
}
});
mocha.it('returns 401 for a wrong password', async () => {
Comment thread
huss marked this conversation as resolved.
const res = await chai.request(app).post('/api/loginLogout/login')
Expand All @@ -37,10 +43,15 @@ mocha.describe('verification API', () => {
.send({ username: testUser.username, password: testUser.password });
expect(res).to.have.status(HTTP_CODES.OK);
expect(res).to.be.json;
token = res.body.token;
let token = res.body.token;

const res2 = await chai.request(app).post('/api/verification')
.send({token: token});
.send({ token: token });
expect(res2).to.have.status(HTTP_CODES.OK);

if (token) {
await chai.request(app).post('/api/loginLogout/logout')
.set('token', token);
}
});
});
26 changes: 20 additions & 6 deletions src/server/test/web/maps.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* This file tests the API for retrieving meters, by artificially
* inserting meters prior to executing the test code. */
/* This file tests the API for retrieving maps, by artificially
* inserting maps prior to executing the test code. */

const { chai, mocha, expect, app, testDB, testUser } = require('../common');
const { Map } = require('../../models/Map');
Expand Down Expand Up @@ -49,9 +49,6 @@ function expectMapsToBeEquivalent(maps, length) {
}

mocha.describe('maps API', () => {
mocha.beforeEach(async () => {
// TODO Why is there an empty body here?
});

mocha.it('returns nothing when no map is present', async () => {
const res = await chai.request(app).get('/api/maps');
Expand Down Expand Up @@ -80,10 +77,19 @@ mocha.describe('maps API', () => {
// Since this .before is in the middle of tests, it should not have issues as
// documented in usersTest.js.
mocha.before(async () => {
Comment thread
huss marked this conversation as resolved.
Outdated
// login
let res = await chai.request(app).post('/api/loginLogout/login')
.send({ username: testUser.username, password: testUser.password });
token = res.body.token;
});
mocha.after(async () => {
// logout
if (token) {
await chai.request(app).post('/api/loginLogout/logout')
.set('token', token);
}
});

mocha.it('returns all maps', async () => {
const conn = testDB.getConnection();
await new Map(undefined, 'Map 1', true, null, 'default', moment('2000-10-10'), origin, opposite, 'placeholder', 1.0, 0.1).insert(conn);
Expand Down Expand Up @@ -119,6 +125,14 @@ mocha.describe('maps API', () => {
.send({ username: unauthorizedUser.username, password: unauthorizedUser.password });
token = res.body.token;
});
mocha.afterEach(async () => {
// logout
if (token) {
await chai.request(app).post('/api/loginLogout/logout')
.set('token', token);
}
});

mocha.it(`should reject requests from ${role} to create maps`, async () => {
// get maps
let res = await chai.request(app).post('/api/maps/create').set('token', token);
Expand Down Expand Up @@ -170,7 +184,7 @@ mocha.describe('maps API', () => {
expect(res.body).to.have.property('name', 'Map 2');
});

mocha.it('responds appropriately when the meter in question does not exist', async () => {
mocha.it('responds appropriately when the map in question does not exist', async () => {
const conn = testDB.getConnection();
const map = new Map(undefined, 'Map', true, null, 'default', moment('2000-10-10'), origin, opposite, 'placeholder', 0.0, 0.0);
await map.insert(conn);
Expand Down
42 changes: 32 additions & 10 deletions src/server/test/web/meters.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,16 +157,31 @@ mocha.describe('meters API', () => {

mocha.describe('Admin role & CSV role:', () => {
for (const role in User.role) {
if (User.role[role] !== User.role.OBVIUS && User.role[role] !== User.role.EXPORT) {
if (User.role[role] == User.role.ADMIN || User.role[role] == User.role.CSV) {
let token;
// Since this .before is in the middle of tests, it should not have issues as
// documented in usersTest.js.
mocha.before(async () => {
let res = await chai.request(app).post('/api/loginLogout/login')
.send({ username: testUser.username, password: testUser.password });
token = res.body.token;
});
mocha.it('returns all meters', async () => {
mocha.beforeEach(async () => {
// insert test user

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

space indenting should be tabs.

const conn = testDB.getConnection();
const password = 'password';
const hashedPassword = await bcrypt.hash(password, 10);
const authorizedUser = new User(undefined, `${role}@example.com`, hashedPassword, User.role[role]);
await authorizedUser.insert(conn);
authorizedUser.password = password;

// login
let res = await chai.request(app).post('/api/loginLogout/login')
.send({ username: authorizedUser.username, password: authorizedUser.password });
token = res.body.token;
});
mocha.afterEach(async () => {
// logout
if (token) {
await chai.request(app).post('/api/loginLogout/logout')
.set('token', token);
}
});

mocha.it(`should return all meters for ${role}`, async () => {
const conn = testDB.getConnection();
await new Meter(undefined, 'Meter 1', '1.1.1.1', true, true, Meter.type.MAMAC, '+01', gps,
'Identified 1', 'notes 1', 10.0, true, true, '01:01:25', '05:05:05', 5.1, 7.3, 1, 'increasing', false,
Expand Down Expand Up @@ -217,7 +232,14 @@ mocha.describe('meters API', () => {
.send({ username: unauthorizedUser.username, password: unauthorizedUser.password });
token = res.body.token;
});

mocha.afterEach(async () => {
// logout
if (token) {
await chai.request(app).post('/api/loginLogout/logout')
.set('token', token);
}
});

mocha.it('should only return visible data', async () => {
const conn = testDB.getConnection();
await new Meter(undefined, 'Meter 1', '1.1.1.1', true, true, Meter.type.MAMAC, '+01', gps,
Expand Down
67 changes: 46 additions & 21 deletions src/server/test/web/preferencesTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* This file tests the API for retrieving meters, by artificially
* inserting meters prior to executing the test code. */
/* This file tests the API for retrieving preferences, by artificially
* inserting preferences prior to executing the test code. */

const { chai, mocha, expect, app, testDB, testUser } = require('../common');
const User = require('../../models/User');
Expand All @@ -13,24 +13,39 @@ const { HTTP_CODES } = require('../../util/httpCodes');
mocha.describe('preferences API', () => {
mocha.describe('modification api', () => {
mocha.describe('edit endpoint', () => {
mocha.it('should accept requests from Admin role', async () => {
let res = await chai.request(app).post('/api/loginLogout/login')
.send({ username: testUser.username, password: testUser.password });
expect(res).to.have.status(HTTP_CODES.OK);
const token = res.body.token;
const preferences = {
displayTitle: 'title',
defaultChartToRender: 'line',
defaultBarStacking: true,
defaultLanguage: 'en',
defaultWarningFileSize: 5,
defaultFileSizeLimit: 25,
defaultAreaNormalization: true,
defaultAreaUnit: 'meters',
defaultMeterReadingFrequency: '1:13:17'
}
res = await chai.request(app).post('/api/preferences').set('token', token).send({ preferences });
expect(res).to.have.status(HTTP_CODES.OK);
const preferences = {
displayTitle: 'title',
defaultChartToRender: 'line',
defaultBarStacking: true,
defaultLanguage: 'en',
defaultWarningFileSize: 5,
defaultFileSizeLimit: 25,
defaultAreaNormalization: true,
defaultAreaUnit: 'meters',
defaultMeterReadingFrequency: '1:13:17'
};
mocha.describe('Admin role: ', () => {
Comment thread
huss marked this conversation as resolved.
let token;
mocha.before(async () => {
// login
let res = await chai.request(app).post('/api/loginLogout/login')
.send({ username: testUser.username, password: testUser.password });
token = res.body.token;
});
mocha.after(async () => {
// logout
if (token) {
await chai.request(app).post('/api/loginLogout/logout')
.set('token', token);
}
});

mocha.it('should accept requests from Admin role', async () => {
res = await chai.request(app).post('/api/preferences')
.set('token', token)
.send({ preferences });
expect(res).to.have.status(HTTP_CODES.OK);
});
});

mocha.describe('Non-Admin roles: ', () => {
Expand All @@ -51,8 +66,18 @@ mocha.describe('preferences API', () => {
.send({ username: unauthorizedUser.username, password: unauthorizedUser.password });
token = res.body.token;
});
mocha.afterEach(async () => {
// logout
if (token) {
await chai.request(app).post('/api/loginLogout/logout')
.set('token', token);
}
});

mocha.it(`should reject requests from ${role}`, async () => {
let res = await chai.request(app).post('/api/preferences').set('token', token);
res = await chai.request(app).post('/api/preferences')
.set('token', token)
.send({ preferences });
expect(res).to.have.status(HTTP_CODES.FORBIDDEN);
});
}
Expand Down
23 changes: 20 additions & 3 deletions src/server/test/web/usersTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* This file tests the API for retrieving meters, by artificially
* inserting meters prior to executing the test code. */
/* This file tests the API for retrieving users, by artificially
* inserting users prior to executing the test code. */

const { chai, mocha, expect, app, testDB, testUser, recreateDB } = require('../common');
const User = require('../../models/User');
Expand All @@ -24,6 +24,13 @@ mocha.describe('Users API', () => {
.send({ username: testUser.username, password: testUser.password });
token = res.body.token;
});
mocha.after(async () => {
if (token) {
await chai.request(app).post('/api/loginLogout/logout')
.set('token', token);
}
});

mocha.it('retrieves users', async () => {
const conn = testDB.getConnection();
const password = await bcrypt.hash('password', 10);
Expand Down Expand Up @@ -118,10 +125,20 @@ mocha.describe('Users API', () => {
.send({ username: unauthorizedUser.username, password: unauthorizedUser.password });
token = res.body.token;
});
mocha.it('should reject request to retrieve users', async () => {
mocha.afterEach(async () => {
// logout
if (token) {
await chai.request(app).post('/api/loginLogout/logout')
.set('token', token);
}
});

mocha.it(`should reject requests from ${role} to retrieve users`, async () => {
// get
const res = await chai.request(app).get('/api/users').set('token', token);
expect(res).to.have.status(HTTP_CODES.FORBIDDEN);
});

mocha.it(`should reject requests from ${role} to create users`, async () => {
// create
const res = await chai.request(app).post('/api/users/create').set('token', token);
Expand Down
Loading