I have this Issues schema:
// Require Mongoose
import mongoose from "mongoose";
import { rolesSchema } from "./roles.js";
import { storyPointSchema } from "./storyPoint.js";
// Define a schema
const Schema = mongoose.Schema;
/**
* Issues Report Schema
*/
export const issuesSchema = new Schema({
team: {
required: true,
type: String,
},
teamRoles: {
type: [rolesSchema],
required: true
},
ticketId: {
type: String,
required: true
},
issueName: {
type: String,
required: true,
},
description: {
type: String,
required: true
},
issueType: {
type: String,
enum: ['story', 'bug', 'task', 'sub-task', 'epic'],
default: 'story',
required: true
},
storyPoints: {
accepted: storyPointSchema,
committed: storyPointSchema,
completed: storyPointSchema,
estimated: storyPointSchema,
actual: storyPointSchema
}
}, {_id: false})
/**
* Calculate Full Name
* Virtual for ticket assignee's full name
*/
issuesSchema.virtual('fullname').get(function () {
let fullName = ""
if (this.firstName && this.lastName) {
fullName = `${this.firstName}, ${this.lastName}`
}
return fullName
})
export const Issues = mongoose.model('Issues', issuesSchema)
Here are the two embedded document schemas:
export const rolesSchema = new Schema({
firstName: {
type: String,
required: true
},
lastName:{
type: String,
required: true
},
role: {
type:String,
required: true
}
})
export const Roles = mongoose.model('Roles', rolesSchema)
// Require Mongoose
import mongoose from "mongoose";
// Define a schema
const Schema = mongoose.Schema;
/**
* Story Point Report Schema
*/
export const storyPointSchema = new Schema([{
storyPoint: {
type: Number,
required: true,
enum: [0,1, 2, 3, 5, 8, 13]
}
}])
In unit testing I can get all errors that the validators throw when required is missing or wrong format data
Here is the validations errors:
{
"errors": {
"description": {
"name": "ValidatorError",
"message": "Path `description` is required.",
"properties": {
"message": "Path `description` is required.",
"type": "required",
"path": "description"
},
"kind": "required",
"path": "description"
},
"issueName": {
"name": "ValidatorError",
"message": "Path `issueName` is required.",
"properties": {
"message": "Path `issueName` is required.",
"type": "required",
"path": "issueName"
},
"kind": "required",
"path": "issueName"
},
"ticketId": {
"name": "ValidatorError",
"message": "Path `ticketId` is required.",
"properties": {
"message": "Path `ticketId` is required.",
"type": "required",
"path": "ticketId"
},
"kind": "required",
"path": "ticketId"
},
"team": {
"name": "ValidatorError",
"message": "Path `team` is required.",
"properties": {
"message": "Path `team` is required.",
"type": "required",
"path": "team"
},
"kind": "required",
"path": "team"
},
"issueType": {
"name": "ValidatorError",
"message": "`foo` is not a valid enum value for path `issueType`.",
"properties": {
"message": "`foo` is not a valid enum value for path `issueType`.",
"type": "enum",
"enumValues": [
"story",
"bug",
"task",
"sub-task",
"epic"
],
"path": "issueType",
"value": "foo"
},
"kind": "enum",
"path": "issueType",
"value": "foo"
}
},
"_message": "Issues validation failed",
"name": "ValidationError",
"message": "Issues validation failed: description: Path `description` is required., issueName: Path `issueName` is required., ticketId: Path `ticketId` is required., team: Path `team` is required., issueType: `foo` is not a valid enum value for path `issueType`."
Can you see any issues with these schemas to see why both embedded documents fail to register any errors relevant to roles or story points?
To get default or any validation working for the Story Points I had to flatten this schema ( As per Mongoose's documentation where it says embedded sub documents can be tricky as they don't actually belong to document so validation won't work.
Here is the updated storyPointSchema:
// Require Mongoose
import mongoose from "mongoose";
import { ActoValidator } from "../services/validators/ActoValidator.js";
const Validator = new ActoValidator();
// Define a schema
const Schema = mongoose.Schema;
/**
* Story Point Report Schema
*/
export const storyPointSchema = new Schema({
accepted:{
type: Number,
enum: [0,1, 2, 3, 5, 8, 13],
},
committed: {
type: Number,
enum: [0,1, 2, 3, 5, 8, 13],
},
completed: {
type: Number,
enum: [0,1, 2, 3, 5, 8, 13],
},
estimated: {
type: Number,
enum: [0,1, 2, 3, 5, 8, 13],
},
actual: {
type: Number,
enum: [0,1, 2, 3, 5, 8, 13],
},
})
And then the issue schema is:
// Require Mongoose
import mongoose from "mongoose";
import { rolesSchema } from "./roles.js";
import { storyPointSchema } from "./storyPoint.js";
// Define a schema
const Schema = mongoose.Schema;
/**
* Issues Report Schema
*/
export const issuesSchema = new Schema({
team: {
required: true,
type: String
},
teamRoles: {
type: [rolesSchema],
required: true
},
ticketId: {
type: String,
required: true
},
issueName: {
type: String,
required: true,
},
description: {
type: String,
required: true
},
issueType: {
type: String,
enum: ['story', 'bug', 'task', 'sub-task', 'epic'],
default: 'story',
required: true
},
storyPoints: {
type: storyPointSchema,
required: [true, "`the estimated story point field` is required, either 0, 1, 2, 3, 5, 8, or 13"],
}
}, {_id: false})
/**
* Calculate Full Name
* Virtual for ticket assignee's full name
*/
issuesSchema.virtual('fullname').get(function () {
let fullName = ""
if (this.firstName && this.lastName) {
fullName = `${this.firstName}, ${this.lastName}`
}
return fullName
})
/**
* Team roles validation for the array items
*/
issuesSchema.path('teamRoles').validate(function(teamRoles){
if(!teamRoles){return false}
else if(teamRoles.length === 0){return false}
return true;
}, '`issueRole` is required. There must be at least one role added to each issue');
export const Issues = mongoose.model('Issues', issuesSchema)
This now has the appropriate errors:
{
"errors": {
"storyPoints": {
"name": "ValidatorError",
"message": "`the estimated story point field` is required, either 0, 1, 2, 3, 5, 8, or 13",
"properties": {
"message": "`the estimated story point field` is required, either 0, 1, 2, 3, 5, 8, or 13",
"type": "required",
"path": "storyPoints"
},
"kind": "required",
"path": "storyPoints"
},
"description": {
"name": "ValidatorError",
"message": "Path `description` is required.",
"properties": {
"message": "Path `description` is required.",
"type": "required",
"path": "description"
},
"kind": "required",
"path": "description"
},
"issueName": {
"name": "ValidatorError",
"message": "Path `issueName` is required.",
"properties": {
"message": "Path `issueName` is required.",
"type": "required",
"path": "issueName"
},
"kind": "required",
"path": "issueName"
},
"ticketId": {
"name": "ValidatorError",
"message": "Path `ticketId` is required.",
"properties": {
"message": "Path `ticketId` is required.",
"type": "required",
"path": "ticketId"
},
"kind": "required",
"path": "ticketId"
},
"team": {
"name": "ValidatorError",
"message": "Path `team` is required.",
"properties": {
"message": "Path `team` is required.",
"type": "required",
"path": "team"
},
"kind": "required",
"path": "team"
},
"teamRoles": {
"name": "ValidatorError",
"message": "`issueRole` is required. There must be at least one role added to each issue",
"properties": {
"message": "`issueRole` is required. There must be at least one role added to each issue",
"type": "user defined",
"path": "teamRoles",
"value": []
},
"kind": "user defined",
"path": "teamRoles",
"value": []
}
},
"_message": "Issues validation failed",
"name": "ValidationError",
"message": "Issues validation failed: storyPoints: `the estimated story point field` is required, either 0, 1, 2, 3, 5, 8, or 13, description: Path `description` is required., issueName: Path `issueName` is required., ticketId: Path `ticketId` is required., team: Path `team` is required., teamRoles: `issueRole` is required. There must be at least one role added to each issue"
I hope this helps someone else :shrug"