feat(tests): add Jest+Supertest infrastructure with jump route suite (14 tests)

- Extract Express app creation into src/createApp.js to enable testing without starting the server
- Add Jest, Supertest, test helpers (createTestApp, auth token generator)
- Write 14 integration tests for skydive/jumps: auth protection, CRUD, ownership checks

Bugs caught and fixed by the test suite:
- MongoDB models: author field typed as Schema.Types.UUID (Mongoose 6 rejects string UUIDs) → changed to String
- Jump.toJSONFor: called toProfileJSONFor on a UUID string → guarded with typeof check
- exceptions.handler: used err.statusCode but express-jwt throws err.status → returns 500 on 401 errors
- Jump.count(query): deprecated Mongoose method was ignoring the filter → replaced with countDocuments
- jumps.routes GET /: $or query included non-schema field "title" stripped by strictQuery, leaving {} (match-all) → replaced with slug/lieu search
- $regex: was passing a JS RegExp object which serializes to {} in MongoDB → now passes raw string
This commit is contained in:
2026-04-26 01:23:01 +02:00
parent 4c765945b3
commit da1f9437ab
21 changed files with 4068 additions and 163 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ var AeronefSchema = new mongoose.Schema({
slug: { type: String, lowercase: true, unique: true },
aeronef: String,
imat: String,
author: { type: mongoose.Schema.Types.UUID, ref: 'User' }
author: { type: String }
}, {timestamps: true, toJSON: {virtuals: true}});
AeronefSchema.pre('validate', function (next) {
+1 -1
View File
@@ -8,7 +8,7 @@ var ApplicationSchema = new mongoose.Schema({
slug: { type: String, lowercase: true, unique: true },
title: String,
description: String,
author: { type: mongoose.Schema.Types.UUID, ref: 'User' }
author: { type: String }
}, { timestamps: true, toJSON: { virtuals: true } });
ApplicationSchema.plugin(uniqueValidator, { message: 'is already taken' });
+1 -1
View File
@@ -5,7 +5,7 @@ var CanopySchema = new mongoose.Schema({
slug: { type: String, lowercase: true, unique: true },
voile: String,
taille: Number,
author: { type: mongoose.Schema.Types.UUID, ref: 'User' }
author: { type: String }
}, {timestamps: true, toJSON: {virtuals: true}});
CanopySchema.pre('validate', function (next) {
+1 -1
View File
@@ -5,7 +5,7 @@ var DropzoneSchema = new mongoose.Schema({
slug: { type: String, lowercase: true, unique: true },
lieu: String,
oaci: String,
author: { type: mongoose.Schema.Types.UUID, ref: 'User' }
author: { type: String }
}, {timestamps: true, toJSON: {virtuals: true}});
DropzoneSchema.pre('validate', function (next) {
+4 -2
View File
@@ -25,7 +25,7 @@ var JumpSchema = new mongoose.Schema({
video: String,
files: [{ type: mongoose.Schema.Types.ObjectId, ref: 'JumpFile' }],
x2data: { type: mongoose.Schema.Types.ObjectId, ref: 'X2DataLog' },
author: { type: mongoose.Schema.Types.UUID, ref: 'User' }
author: { type: String }
}, {timestamps: true, toJSON: {virtuals: true}});
JumpSchema.plugin(uniqueValidator, { message: 'is already taken' });
@@ -79,7 +79,9 @@ JumpSchema.methods.toJSONFor = function(user) {
x2data: this.x2data ? this.x2data.toJSONFor() : null,
createdAt: this.createdAt,
updatedAt: this.updatedAt,
author: this.author.toProfileJSONFor(user)
author: this.author && typeof this.author.toProfileJSONFor === 'function'
? this.author.toProfileJSONFor(user)
: this.author ?? null
};
};
+1 -1
View File
@@ -11,7 +11,7 @@ var JumpFileSchema = new mongoose.Schema({
enum : ['csv', 'image', 'kml', 'video'],
default: 'video'
},
author: { type: mongoose.Schema.Types.UUID, ref: 'User' }
author: { type: String }
}, {timestamps: true, toJSON: {virtuals: true}});
JumpFileSchema.plugin(uniqueValidator, { message: 'is already taken' });
+1 -1
View File
@@ -60,7 +60,7 @@ var X2DataLogSchema = new mongoose.Schema({
],
date: String,
createdOn: String,
author: { type: mongoose.Schema.Types.UUID, ref: 'User' }
author: { type: String }
}, {timestamps: true, toJSON: {virtuals: true}});
X2DataLogSchema.methods.toJSONFor = function() {
+1 -1
View File
@@ -24,7 +24,7 @@ var HWClanSchema = new mongoose.Schema({
title: String,
topActivity: String,
topDungeon: String,
author: { type: mongoose.Schema.Types.UUID, ref: 'User' }
author: { type: String }
}, {timestamps: true, toJSON: {virtuals: true}});
HWClanSchema.plugin(uniqueValidator, { message: 'is already taken' });
+2 -2
View File
@@ -47,7 +47,7 @@ var HWMemberSchemaOld = new mongoose.Schema({
scoreGifts: Number,
warGifts: Number,
rewards: Number,
author: { type: mongoose.Schema.Types.UUID, ref: 'User' }
author: { type: String }
}, {timestamps: true, toJSON: {virtuals: true}});
*/
var HWMemberSchema = new mongoose.Schema({
@@ -104,7 +104,7 @@ var HWMemberSchema = new mongoose.Schema({
scoreGifts: Number,
warGifts: Number,
rewards: Number,
author: { type: mongoose.Schema.Types.UUID, ref: 'User' }
author: { type: String }
}, {timestamps: true, toJSON: {virtuals: true}});
HWMemberSchema.plugin(uniqueValidator, { message: 'is already taken' });