From 2510936df1cf0e2a06b01bf7263e3925d906383e Mon Sep 17 00:00:00 2001 From: Tony Kan Date: Sun, 13 Oct 2024 23:54:30 -0700 Subject: [PATCH] refactor(problem-generators): Migrate problem generator to separate NPM package - Migrated the problem generator code to a new NPM package named `mpclab`. - Updated import statements from `require("/problem-generators")` to `require("mpclab")`. - Adjusted corresponding tests to ensure compatibility with the new package. - Revised documentation to reflect the new import paths and usage instructions. Related to issue #4 --- README.md | 12 + docs/API.md | 4 +- package-lock.json | 17 +- package.json | 3 +- src/controllers/problemController.js | 16 +- src/controllers/taskController.js | 2 +- src/problem-generators/index.js | 170 --------- src/problem-generators/index.json | 360 ------------------ .../graphingLinearEquations.js | 134 ------- .../linear-equations/pointSlopeForm.js | 139 ------- .../linear-equations/slopeInterceptForm.js | 136 ------- .../algebra/linear-equations/standardForm.js | 74 ---- .../linear-equations/withAbsoluteValue.js | 127 ------ .../algebra/linear-equations/withFractions.js | 84 ---- .../linear-equations/withParentheses.js | 89 ----- src/utils/randomUtils.js | 36 -- tests/controllers/problemController.test.js | 15 +- tests/controllers/taskController.test.js | 4 +- 18 files changed, 50 insertions(+), 1372 deletions(-) delete mode 100644 src/problem-generators/index.js delete mode 100644 src/problem-generators/index.json delete mode 100644 src/problem-generators/math/algebra/linear-equations/graphingLinearEquations.js delete mode 100644 src/problem-generators/math/algebra/linear-equations/pointSlopeForm.js delete mode 100644 src/problem-generators/math/algebra/linear-equations/slopeInterceptForm.js delete mode 100644 src/problem-generators/math/algebra/linear-equations/standardForm.js delete mode 100644 src/problem-generators/math/algebra/linear-equations/withAbsoluteValue.js delete mode 100644 src/problem-generators/math/algebra/linear-equations/withFractions.js delete mode 100644 src/problem-generators/math/algebra/linear-equations/withParentheses.js delete mode 100644 src/utils/randomUtils.js diff --git a/README.md b/README.md index f37c6b9..febed86 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,18 @@ The server uses Jest for testing. To run the tests, use the following command. npm test ``` +## Acknowledgements + +We would like to thank the following libraries and tools for making this project possible: + +- [Express.js](https://expressjs.com/): A fast, unopinionated, minimalist web framework for Node.js. +- [MongoDB](https://www.mongodb.com/): A NoSQL database program that uses JSON-like documents with optional schemas. +- [Jest](https://jestjs.io/): A delightful JavaScript testing framework with a focus on simplicity. +- [Nodemailer](https://nodemailer.com/): A module for Node.js to send emails easily. +- [JWT](https://jwt.io/): A compact, URL-safe means of representing claims to be transferred between two parties. +- [bcrypt](https://www.npmjs.com/package/bcrypt): A library to help you hash passwords. +- [mpclab](https://www.npmjs.com/package/mpclab): A problem generator for mathematics, physics, and chemistry. + ## License This project is licensed under the GNU General Public License v3.0 - see the [LICENSE](LICENSE) file for details. diff --git a/docs/API.md b/docs/API.md index 0ec316e..37bc749 100644 --- a/docs/API.md +++ b/docs/API.md @@ -2856,7 +2856,9 @@ The API uses JWT (JSON Web Token) for authentication. To access protected routes - **Query Parameters**: - - `options`: The problem generation options. + - `options`: The problem generation options. (Optional, object (Use JSON string)) + + > **Note:** The problem generation options are passed as a query parameter. Please use `JSON.stringify` to pass the object. - **Response**: diff --git a/package-lock.json b/package-lock.json index dd35f90..69c898b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "jsonwebtoken": "^9.0.2", "mathjs": "^13.1.1", "mongoose": "^8.6.2", + "mpclab": "^0.1.0", "nodemailer": "^6.9.15" }, "devDependencies": { @@ -3590,11 +3591,11 @@ } }, "node_modules/mathjs": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-13.1.1.tgz", - "integrity": "sha512-duaSAy7m4F+QtP1Dyv8MX2XuxcqpNDDlGly0SdVTCqpAmwdOFWilDdQKbLdo9RfD6IDNMOdo9tIsEaTXkconlQ==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-13.2.0.tgz", + "integrity": "sha512-P5PZoiUX2Tkghkv3tsSqlK0B9My/ErKapv1j6wdxd0MOrYQ30cnGE4LH/kzYB2gA5rN46Njqc4cFgJjaxgijoQ==", "dependencies": { - "@babel/runtime": "^7.25.4", + "@babel/runtime": "^7.25.6", "complex.js": "^2.1.1", "decimal.js": "^10.4.3", "escape-latex": "^1.2.0", @@ -3870,6 +3871,14 @@ "node": ">=4.0.0" } }, + "node_modules/mpclab": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/mpclab/-/mpclab-0.1.0.tgz", + "integrity": "sha512-lX1CN+vGkT9RMCweZwu7Q5NjWa2Rwm5sRHzVTknYDae5gboZHLeWIKfvNQt0nWkCi8Fyt3VjhfHCAlM+LkB/BQ==", + "dependencies": { + "mathjs": "^13.2.0" + } + }, "node_modules/mquery": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", diff --git a/package.json b/package.json index 9b0e170..a3d03e0 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "jsonwebtoken": "^9.0.2", "mathjs": "^13.1.1", "mongoose": "^8.6.2", + "mpclab": "^0.1.0", "nodemailer": "^6.9.15" }, "devDependencies": { @@ -15,6 +16,6 @@ }, "scripts": { "start": "node server.js", - "test": "jest --verbose --silent --coverage --forceExit --config=tests/jest.config.js" + "test": "jest --verbose --silent --coverage --ci --forceExit --config=tests/jest.config.js" } } diff --git a/src/controllers/problemController.js b/src/controllers/problemController.js index 6d8014d..451e946 100644 --- a/src/controllers/problemController.js +++ b/src/controllers/problemController.js @@ -3,8 +3,7 @@ * @description Controller for problem generation. */ -const index = require("../problem-generators/index.json"); -const ProblemGenerator = require("../problem-generators"); +const ProblemGenerator = require("mpclab"); const problemGenerator = new ProblemGenerator(); /** @@ -13,7 +12,10 @@ const problemGenerator = new ProblemGenerator(); * @param {Response} res - The response object. */ getIndex = (req, res) => { - res.success(index, "Problem generator index retrieved successfully."); + res.success( + problemGenerator.index, + "Problem generator index retrieved successfully." + ); }; /** @@ -22,12 +24,12 @@ getIndex = (req, res) => { * @param {Response} res - The response object. */ generateProblem = (req, res) => { - const topicsString = req.params[0]; - const { options } = req.query; + try { + const topicsString = req.params[0]; + const options = JSON.parse(req.query.options || "{}"); - const topics = topicsString.split("/"); + const topics = topicsString.split("/"); - try { const problem = problemGenerator.generateOne({ path: topics, options: options, diff --git a/src/controllers/taskController.js b/src/controllers/taskController.js index 2c12cf9..ab3e912 100644 --- a/src/controllers/taskController.js +++ b/src/controllers/taskController.js @@ -6,7 +6,7 @@ const taskService = require("../services/taskService"); const classService = require("../services/classService"); -const ProblemGenerator = require("../problem-generators"); +const ProblemGenerator = require("mpclab"); const problemGenerator = new ProblemGenerator(); const validationUtils = require("../utils/validationUtils"); diff --git a/src/problem-generators/index.js b/src/problem-generators/index.js deleted file mode 100644 index 13476bc..0000000 --- a/src/problem-generators/index.js +++ /dev/null @@ -1,170 +0,0 @@ -/** - * @file src/problem-generators/index.js - * @description This file is the entry point for all problem generators. It loads all problem generators from the file system and generates problems for the specified topics. - */ - -const fs = require("fs"); -const path = require("path"); - -class ProblemGenerator { - /** - * @constructor - Create a new ProblemGenerator instance. - * @param {Object} config - The configuration for the ProblemGenerator. - * @param {number} config.maxCount - The maximum number of problems to generate. - */ - constructor(config = {}) { - this.maxCount = config.maxCount || 1000; - - this.index = JSON.parse( - fs.readFileSync(path.join(__dirname, "index.json"), "utf8") - ); - this.generators = this.loadGenerators(); - this.parameters = this.loadParameters(); - } - - /** - * @function loadGenerators - Load all problem generators from the file system. - * @returns {Object} - The problem generators for the specified topic. - */ - loadGenerators() { - const generators = {}; - - const loadGenerator = (node, currentPath) => { - let generators = {}; - - if (node.topics) { - for (const subtopic in node.topics) { - generators[subtopic] = loadGenerator(node.topics[subtopic], [ - ...currentPath, - subtopic, - ]); - } - } else { - const generatorPath = path.join(__dirname, ...currentPath); - - const generator = require(generatorPath); - generators = generator; - } - - return generators; - }; - - for (const subject in this.index) { - generators[subject] = loadGenerator(this.index[subject], [subject]); - } - - return generators; - } - - /** - * @function loadParameters - Load all problem parameters from the file system. - * @returns {Object} - The problem parameters for the specified topic. - */ - loadParameters() { - const generators = {}; - - const loadGenerator = (node) => { - let generators = {}; - - if (node.topics) { - for (const subtopic in node.topics) { - generators[subtopic] = loadGenerator(node.topics[subtopic]); - } - } else { - const parameters = node.parameters; - generators = parameters; - } - - return generators; - }; - - for (const subject in this.index) { - generators[subject] = loadGenerator(this.index[subject]); - } - - return generators; - } - - /** - * @function generate - Generate problems for the specified topics. - * @param {Object} options - The options for generating the problems. - * @param {Array} options.topics - The topics for generating the problems. - * @param {boolean} options.shuffle - Whether to shuffle the problems - * @returns {Array} - The generated problems. - */ - generate(options) { - const problems = []; - - try { - if (!options.topics || options.topics.length === 0) { - throw new Error("No topics specified"); - } - - for (const topic of options.topics) { - const path = topic.path; - const topicOptions = topic.options; - - const count = Math.min(topicOptions.count || 5, this.maxCount); - - const generator = path.reduce((acc, cur) => acc[cur], this.generators); - const parameters = path.reduce((acc, cur) => acc[cur], this.parameters); - - if (!generator || !parameters) { - throw new Error("Generator not found"); - } - - for (const key in parameters) { - if (topicOptions[key] === undefined) { - topicOptions[key] = parameters[key]; - } - } - - for (const key in topicOptions) { - if (parameters[key] === undefined && key !== "count") { - delete topicOptions[key]; - } - } - - const topicProblems = []; - for (let i = 0; i < count; i++) { - const problem = generator(topicOptions); - topicProblems.push(problem); - } - - problems.push(...topicProblems); - } - - if (options.shuffle) { - problems.sort(() => Math.random() - 0.5); - } - } catch (e) { - throw e; - } - - return problems; - } - - /** - * @function generateOne - Generate a single problem for the specified topics. - * @param {Object} topic - The topic for generating the problem. - * @returns {Object} - The generated problem. - */ - generateOne(topic) { - const problems = this.generate({ topics: [topic], shuffle: false }); - return problems[0]; - } - - /** - * @function testDuplicate - Test for duplicate problems in the generated problems. - * @param {Array} problems - The generated problems. - * @returns {number} - The number of duplicate problems. - */ - testDuplicate(problems) { - const problemSet = new Set( - problems.map((problem) => JSON.stringify(problem)) - ); - return problems.length - problemSet.size; - } -} - -module.exports = ProblemGenerator; diff --git a/src/problem-generators/index.json b/src/problem-generators/index.json deleted file mode 100644 index 2833e51..0000000 --- a/src/problem-generators/index.json +++ /dev/null @@ -1,360 +0,0 @@ -{ - "math": { - "name": "Math", - "description": "Mathematics problems, including algebra, geometry, calculus, and more.", - "topics": { - "algebra": { - "name": "Algebra", - "description": "Algebra problems, including including expressions, equations, and more.", - "topics": { - "linear-equations": { - "name": "Linear Equations", - "description": "Problems involving linear equations.", - "topics": { - "standardForm": { - "name": "Standard Form", - "description": "Problems involving linear equations in standard form (ax + b = c).", - "parameters": { - "minCoefficient": { - "type": "number", - "name": "Minimum Coefficient", - "description": "The minimum value for the coefficient a.", - "default": -20, - "min": -10000, - "max": 10000 - }, - "maxCoefficient": { - "type": "number", - "name": "Maximum Coefficient", - "description": "The maximum value for the coefficient a.", - "default": 20, - "min": -10000, - "max": 10000 - }, - "minConstant": { - "type": "number", - "name": "Minimum Constant", - "description": "The minimum value for the constant b.", - "default": -20, - "min": -10000, - "max": 10000 - }, - "maxConstant": { - "type": "number", - "name": "Maximum Constant", - "description": "The maximum value for the constant b.", - "default": 20, - "min": -10000, - "max": 10000 - }, - "minSolution": { - "type": "number", - "name": "Minimum Solution", - "description": "The minimum value for the solution c.", - "default": -20, - "min": -10000, - "max": 10000 - }, - "maxSolution": { - "type": "number", - "name": "Maximum Solution", - "description": "The maximum value for the solution c.", - "default": 20, - "min": -10000, - "max": 10000 - } - } - }, - "withFractions": { - "name": "With Fractions", - "description": "Problems involving linear equations with fractions (ax/b = c).", - "parameters": { - "minCoefficient": { - "type": "number", - "name": "Minimum Coefficient", - "description": "The minimum value for the coefficient a.", - "default": -20, - "min": -10000, - "max": 10000 - }, - "maxCoefficient": { - "type": "number", - "name": "Maximum Coefficient", - "description": "The maximum value for the coefficient a.", - "default": 20, - "min": -10000, - "max": 10000 - }, - "minDenominator": { - "type": "number", - "name": "Minimum Denominator", - "description": "The minimum value for the denominator(b) of the fraction.", - "default": 2, - "min": 2, - "max": 10000 - }, - "maxDenominator": { - "type": "number", - "name": "Maximum Denominator", - "description": "The maximum value for the denominator(b) of the fraction.", - "default": 10, - "min": 2, - "max": 10000 - }, - "minSolution": { - "type": "number", - "name": "Minimum Solution", - "description": "The minimum value for the solution c.", - "default": -20, - "min": -10000, - "max": 10000 - }, - "maxSolution": { - "type": "number", - "name": "Maximum Solution", - "description": "The maximum value for the solution c.", - "default": 20, - "min": -10000, - "max": 10000 - } - } - }, - "withParentheses": { - "name": "With Parentheses", - "description": "Problems involving linear equations with parentheses (a(x + b) = c).", - "parameters": { - "minCoefficient": { - "type": "number", - "name": "Minimum Coefficient", - "description": "The minimum value for the coefficient a.", - "default": -20, - "min": -10000, - "max": 10000 - }, - "maxCoefficient": { - "type": "number", - "name": "Maximum Coefficient", - "description": "The maximum value for the coefficient a.", - "default": 20, - "min": -10000, - "max": 10000 - }, - "minConstant": { - "type": "number", - "name": "Minimum Constant", - "description": "The minimum value for the constant b.", - "default": -20, - "min": -10000, - "max": 10000 - }, - "maxConstant": { - "type": "number", - "name": "Maximum Constant", - "description": "The maximum value for the constant b.", - "default": 20, - "min": -10000, - "max": 10000 - }, - "minSolution": { - "type": "number", - "name": "Minimum Solution", - "description": "The minimum value for the solution c.", - "default": -20, - "min": -10000, - "max": 10000 - }, - "maxSolution": { - "type": "number", - "name": "Maximum Solution", - "description": "The maximum value for the solution c.", - "default": 20, - "min": -10000, - "max": 10000 - } - } - }, - "withAbsoluteValue": { - "name": "With Absolute Value", - "description": "Problems involving linear equations with absolute value (|ax + b| = c).", - "parameters": { - "minCoefficient": { - "type": "number", - "name": "Minimum Coefficient", - "description": "The minimum value for the coefficient a.", - "default": -20, - "min": -10000, - "max": 10000 - }, - "maxCoefficient": { - "type": "number", - "name": "Maximum Coefficient", - "description": "The maximum value for the coefficient a.", - "default": 20, - "min": -10000, - "max": 10000 - }, - "minConstant": { - "type": "number", - "name": "Minimum Constant", - "description": "The minimum value for the constant b.", - "default": -20, - "min": -10000, - "max": 10000 - }, - "maxConstant": { - "type": "number", - "name": "Maximum Constant", - "description": "The maximum value for the constant b.", - "default": 20, - "min": -10000, - "max": 10000 - }, - "minSolution": { - "type": "number", - "name": "Minimum Solution", - "description": "The minimum value for the solution c.", - "default": -20, - "min": -10000, - "max": 10000 - }, - "maxSolution": { - "type": "number", - "name": "Maximum Solution", - "description": "The maximum value for the solution c.", - "default": 20, - "min": -10000, - "max": 10000 - } - } - }, - "slopeInterceptForm": { - "name": "Slope-Intercept Form", - "description": "Problems involving linear equations in slope-intercept form (y = mx + b), solving for slope and y-intercept.", - "parameters": { - "isMCQ": { - "type": "boolean", - "name": "Multiple Choice", - "description": "Whether the problem is multiple choice.", - "default": true - }, - "isSimplified": { - "type": "boolean", - "name": "Simplified", - "description": "Whether the problem is simplified.", - "default": false - }, - "minSlope": { - "type": "number", - "name": "Minimum Slope", - "description": "The minimum value for the slope m.", - "default": -20, - "min": -10000, - "max": 10000 - }, - "maxSlope": { - "type": "number", - "name": "Maximum Slope", - "description": "The maximum value for the slope m.", - "default": 20, - "min": -10000, - "max": 10000 - }, - "minYIntercept": { - "type": "number", - "name": "Minimum Y-Intercept", - "description": "The minimum value for the y-intercept b.", - "default": -20, - "min": -10000, - "max": 10000 - }, - "maxYIntercept": { - "type": "number", - "name": "Maximum Y-Intercept", - "description": "The maximum value for the y-intercept b.", - "default": 20, - "min": -10000, - "max": 10000 - } - } - }, - "pointSlopeForm": { - "name": "Point-Slope Form", - "description": "Problems involving linear equations in point-slope form (y - y1 = m(x - x1)), solving for slope and (x1, y1).", - "parameters": { - "isMCQ": { - "type": "boolean", - "name": "Multiple Choice", - "description": "Whether the problem is multiple choice.", - "default": true - }, - "isSimplified": { - "type": "boolean", - "name": "Simplified", - "description": "Whether the problem is simplified.", - "default": false - }, - "minSlope": { - "type": "number", - "name": "Minimum Slope", - "description": "The minimum value for the slope m.", - "default": -20, - "min": -10000, - "max": 10000 - }, - "maxSlope": { - "type": "number", - "name": "Maximum Slope", - "description": "The maximum value for the slope m.", - "default": 20, - "min": -10000, - "max": 10000 - }, - "minPoint": { - "type": "number", - "name": "Minimum Point", - "description": "The minimum value for the point (x1, y1).", - "default": -20, - "min": -10000, - "max": 10000 - }, - "maxPoint": { - "type": "number", - "name": "Maximum Point", - "description": "The maximum value for the point (x1, y1).", - "default": 20, - "min": -10000, - "max": 10000 - } - } - }, - "graphingLinearEquations": { - "name": "Graphing Linear Equations", - "description": "Problems involving graphing linear equations. Given a linear equation, graph the line.", - "parameters": { - "includeStandard": { - "type": "boolean", - "name": "Include Standard Form", - "description": "Whether to include the standard form option.", - "default": true - }, - "includeSlopeIntercept": { - "type": "boolean", - "name": "Include Slope-Intercept Form", - "description": "Whether to include the slope-intercept form option.", - "default": true - }, - "includePointSlope": { - "type": "boolean", - "name": "Include Point-Slope Form", - "description": "Whether to include the point-slope form option.", - "default": true - } - } - } - } - } - } - } - } - } -} \ No newline at end of file diff --git a/src/problem-generators/math/algebra/linear-equations/graphingLinearEquations.js b/src/problem-generators/math/algebra/linear-equations/graphingLinearEquations.js deleted file mode 100644 index 0f3d1cb..0000000 --- a/src/problem-generators/math/algebra/linear-equations/graphingLinearEquations.js +++ /dev/null @@ -1,134 +0,0 @@ -/** - * @file src/problem-generators/math/algebra/linear-equations/graphingLinearEquations.js - * @description Generates problems for graphing linear equations. (standard form, slope-intercept form, point-slope form) - */ - -const { randomInt, randomElement } = require("../../../../utils/randomUtils"); - -/** - * @function generateProblem - Generate a problem for graphing a linear equation. - * @param {Object} options - The options for generating the problem. - * @param {boolean} options.includeStandard - Whether to include the standard form option. - * @param {boolean} options.includeSlopeIntercept - Whether to include the slope-intercept form option. - * @param {boolean} options.includePointSlope - Whether to include the point-slope form option. - * @returns {Object} - The linear equation graphing problem. - */ -const generateProblem = (options) => { - let equation; - const m = randomInt(-5, 5); - const b = randomInt(-10, 10); - const x1 = randomInt(-5, 5); - const y1 = randomInt(-10, 10); - - const bSign = b < 0 ? "-" : "+"; - const y1Sign = y1 < 0 ? "-" : "+"; - const x1Sign = x1 < 0 ? "-" : "+"; - const absB = Math.abs(b); - const absY1 = Math.abs(y1); - const absX1 = Math.abs(x1); - - const forms = []; - if (options.includeStandard) forms.push("standard"); - if (options.includeSlopeIntercept) forms.push("slopeIntercept"); - if (options.includePointSlope) forms.push("pointSlope"); - - const selectedForm = forms.length > 0 ? randomElement(forms) : "standard"; - - let xIntercept = null, - yIntercept = null; - switch (selectedForm) { - case "standard": { - const a = randomInt(-5, 5); - equation = `${a}x ${bSign} ${absB}y = ${b * x1 + a * y1}`; - if (a !== 0) xIntercept = (b * x1 + a * y1) / a; - if (b !== 0) yIntercept = (b * x1 + a * y1) / b; - break; - } - case "slopeIntercept": { - equation = `y = ${m}x ${bSign} ${absB}`; - xIntercept = m !== 0 ? -b / m : null; - yIntercept = b; - break; - } - case "pointSlope": { - equation = `y ${y1Sign} ${absY1} = ${m}(x ${x1Sign} ${absX1})`; - xIntercept = m !== 0 ? (y1 - m * x1) / m : null; - yIntercept = y1; - break; - } - } - - const problem = [ - { - type: "text", - value: `Graph the following linear equation:`, - }, - { - type: "formula", - value: equation, - }, - ]; - - const steps = []; - - // Initialize default bounds - let xMin = -10, - xMax = 10, - yMin = -10, - yMax = 10; - const padding = 2; // Additional padding to give a little extra space around the graph - - // Adjust mathBounds based on intercepts, ensuring they are visible and adding padding - if (xIntercept !== null && !isNaN(xIntercept)) { - xMin = Math.min(xMin, Math.floor(xIntercept) - padding); - xMax = Math.max(xMax, Math.ceil(xIntercept) + padding); - } - if (yIntercept !== null && !isNaN(yIntercept)) { - yMin = Math.min(yMin, Math.floor(yIntercept) - padding); - yMax = Math.max(yMax, Math.ceil(yIntercept) + padding); - } - - // Adjust the height and width based on the intercepts - const xRange = xMax - xMin; - const yRange = yMax - yMin; - - // Maintain a reasonable aspect ratio for the graph (optional step) - if (xRange > yRange) { - const diff = xRange - yRange; - yMin -= diff / 2; - yMax += diff / 2; - } else if (yRange > xRange) { - const diff = yRange - xRange; - xMin -= diff / 2; - xMax += diff / 2; - } - - const solution = [ - { - type: "graph", - value: { - renderEngine: "desmos", - expressions: [ - { - type: "expression", - latex: equation, - }, - ], - mathBounds: { - left: xMin, - right: xMax, - bottom: yMin, - top: yMax, - }, - }, - }, - ]; - - return { - problem, - steps, - solution, - }; -}; - -module.exports = generateProblem; diff --git a/src/problem-generators/math/algebra/linear-equations/pointSlopeForm.js b/src/problem-generators/math/algebra/linear-equations/pointSlopeForm.js deleted file mode 100644 index 88b5b3b..0000000 --- a/src/problem-generators/math/algebra/linear-equations/pointSlopeForm.js +++ /dev/null @@ -1,139 +0,0 @@ -/** - * @file src/problem-generators/math/algebra/linear-equations/pointSlopeForm.js - * @description Generates problems for linear equations in point-slope form. In point-slope form, the equation is of the form y - y1 = m(x - x1). (calculation of m, x1, y1) - */ - -const { randomInt } = require("../../../../utils/randomUtils"); - -/** - * @function generateProblem - Generate a linear equation problem in point-slope form. - * @param {Object} options - The options for generating the problem. - * @param {number} options.isMCQ - Whether the problem is multiple choice. - * @param {number} options.isSimplified - Whether the problem is simplified. - * @param {number} options.minSlope - The minimum value for the slope m. - * @param {number} options.maxSlope - The maximum value for the slope m. - * @param {number} options.minPoint - The minimum value for the point (x1, y1). - * @param {number} options.maxPoint - The maximum value for the point (x1, y1). - * @returns {Object} - The linear equation problem in point-slope form. - */ -const generateProblem = (options) => { - const m = randomInt(options.minSlope, options.maxSlope); - const x1 = randomInt(options.minPoint, options.maxPoint); - const y1 = randomInt(options.minPoint, options.maxPoint); - - const x = "x"; - const y = "y"; - - const y1Sign = y1 < 0 ? "-" : "+"; - const x1Sign = x1 < 0 ? "-" : "+"; - const absY1 = Math.abs(y1); - const absX1 = Math.abs(x1); - - let equation = `${y} ${y1Sign} ${absY1} = ${m}(${x} ${x1Sign} ${absX1})`; - - const steps = [ - { - type: "text", - value: `Simplify the equation by rearranging it.`, - }, - { type: "formula", value: equation }, - { - type: "text", - value: `The slope of the line is ${m} and the point is (${x1}, ${y1}).`, - }, - ]; - - // If the problem is not simplified, multiply all terms by a random integer - if (!options.isSimplified) { - const randomMultiplier = randomInt(2, 5); - const y1Sign = y1 * randomMultiplier < 0 ? "-" : "+"; - const x1Sign = x1 < 0 ? "-" : "+"; - const absY1 = Math.abs(y1 * randomMultiplier); - const absX1 = Math.abs(x1); - equation = `${randomMultiplier}${y} ${y1Sign} ${absY1} = ${ - randomMultiplier * m - }(${x} ${x1Sign} ${absX1})`; - } - - // If the problem is not multiple choice, return the problem, steps, and solution - if (!options.isMCQ) { - const problem = [ - { - type: "text", - value: `Write the equation in point-slope form and identify the slope and the point.`, - }, - { type: "formula", value: equation }, - ]; - - const solution = [ - { - type: "numeric", - label: "Slope", - decimal: m, - }, - { - type: "text", - label: "Point (x1, y1)", - value: `(${x1}, ${y1})`, - }, - ]; - - return { - problem, - steps, - solution, - }; - } else { - // Generate multiple choice options - const slopeChoices = [m, m + randomInt(1, 3), m - randomInt(1, 3), m * -1]; - const pointChoices = [ - `(${x1}, ${y1})`, - `(${x1 + 1}, ${y1})`, - `(${x1}, ${y1 + 1})`, - `(${x1 - 1}, ${y1 - 1})`, - ]; - - let choices = []; - for (let i = 0; i < 4; i++) { - choices.push({ - type: "text", - value: `Slope: ${slopeChoices[i]}, Point: ${pointChoices[i]}`, - correct: i === 0, - }); - } - - // Shuffle the choices - choices = choices.sort(() => Math.random() - 0.5); - - let problem = [ - { - type: "text", - value: `Which of the following represents the slope and point of the line?`, - }, - { type: "formula", value: equation }, - { type: "options", value: choices }, - ]; - - const solution = [ - { - type: "choice", - choice: 0, - }, - ]; - - problem[2].value.forEach((choice, index) => { - if (choice.correct) { - solution[0].choice = index; - } - delete choice.correct; - }); - - return { - problem, - steps, - solution, - }; - } -}; - -module.exports = generateProblem; diff --git a/src/problem-generators/math/algebra/linear-equations/slopeInterceptForm.js b/src/problem-generators/math/algebra/linear-equations/slopeInterceptForm.js deleted file mode 100644 index c5c5dbd..0000000 --- a/src/problem-generators/math/algebra/linear-equations/slopeInterceptForm.js +++ /dev/null @@ -1,136 +0,0 @@ -/** - * @file src/problem-generators/math/algebra/linear-equations/slopeInterceptForm.js - * @description Generates problems for linear equations in slope-intercept form. In slope-intercept form, the equation is of the form y = mx + b. (calculation of m and b) - */ - -const { randomInt } = require("../../../../utils/randomUtils"); - -/** - * @function generateProblem - Generate a linear equation problem in slope-intercept form. - * @param {Object} options - The options for generating the problem. - * @param {number} options.isMCQ - Whether the problem is multiple choice. - * @param {number} options.isSimplified - Whether the problem is simplified. - * @param {number} options.minSlope - The minimum value for the slope m. - * @param {number} options.maxSlope - The maximum value for the slope m. - * @param {number} options.minYIntercept - The minimum value for the y-intercept b. - * @param {number} options.maxYIntercept - The maximum value for the y-intercept b. - * @returns {Object} - The linear equation problem in slope-intercept form. - */ -const generateProblem = (options) => { - const m = randomInt(options.minSlope, options.maxSlope); - const b = randomInt(options.minYIntercept, options.maxYIntercept); - - const x = "x"; - const y = "y"; - - let mMultiplier = 1; - let bMultiplier = 1; - let coefficientY = 1; - - let equation = `${y} = ${m}${x} + ${b}`; - - // If the problem is not simplified, multiply all terms by a random integer - if (!options.isSimplified) { - const randomMultiplier = randomInt(2, 5); - equation = `${randomMultiplier}${y} = ${randomMultiplier * m}${x} + ${ - randomMultiplier * b - }`; - coefficientY = randomMultiplier; - mMultiplier *= randomMultiplier; - bMultiplier *= randomMultiplier; - } - - const steps = [ - { - type: "text", - value: `Simplify the equation by dividing all terms by ${coefficientY}.`, - }, - { type: "formula", value: `${y} = ${m}${x} + ${b}` }, - { - type: "text", - value: `The slope of the line is ${m} and the y-intercept is ${b}.`, - }, - ]; - - // If the problem is not multiple choice, return the problem, steps, and solution - if (!options.isMCQ) { - const problem = [ - { - type: "text", - value: `Write the equation in slope-intercept form, and identify the slope and y-intercept.`, - }, - { type: "formula", value: equation }, - ]; - - const solution = [ - { - type: "numeric", - label: "Slope", - decimal: m, - }, - { - type: "numeric", - label: "Y-intercept", - decimal: b, - }, - ]; - - return { - problem, - steps, - solution, - }; - } else { - // Generate multiple choice options - const slopeChoices = [m, m + randomInt(2, 5), m - randomInt(2, 5), m * -1]; - const yInterceptChoices = [ - b, - b + randomInt(2, 5), - b - randomInt(2, 5), - b * -1, - ]; - - let choices = []; - for (let i = 0; i < 4; i++) { - choices.push({ - type: "text", - value: `Slope: ${slopeChoices[i]}, Y-intercept: ${yInterceptChoices[i]}`, - correct: i === 0, - }); - } - - // Shuffle the choices - choices = choices.sort(() => Math.random() - 0.5); - - let problem = [ - { - type: "text", - value: `Which of the following represents the slope and y-intercept of the line?`, - }, - { type: "formula", value: equation }, - { type: "options", value: choices }, - ]; - - const solution = [ - { - type: "choice", - choice: 0, - }, - ]; - - problem[2].value.forEach((choice, index) => { - if (choice.correct) { - solution[0].choice = index; - } - delete choice.correct; - }); - - return { - problem, - steps, - solution, - }; - } -}; - -module.exports = generateProblem; diff --git a/src/problem-generators/math/algebra/linear-equations/standardForm.js b/src/problem-generators/math/algebra/linear-equations/standardForm.js deleted file mode 100644 index 98ff097..0000000 --- a/src/problem-generators/math/algebra/linear-equations/standardForm.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @file src/problem-generators/math/algebra/linear-equations/standardForm.js - * @description Generates problems for linear equations in standard form. In standard form, the equation is of the form ax + b = c. - */ - -const math = require("mathjs"); -const { randomInt, randomVariable } = require("../../../../utils/randomUtils"); - -/** - * @function generateProblem - Generate a linear equation problem. - * @param {Object} options - The options for generating the problem. - * @param {number} options.minCoefficient - The minimum value for the coefficient a. - * @param {number} options.maxCoefficient - The maximum value for the coefficient a. - * @param {number} options.minConstant - The minimum value for the constant b. - * @param {number} options.maxConstant - The maximum value for the constant b. - * @param {number} options.minSolution - The minimum value for the solution c. - * @param {number} options.maxSolution - The maximum value for the solution c. - * @returns {Object} - The linear equation problem. - */ -const generateProblem = (options) => { - const a = randomInt(options.minCoefficient, options.maxCoefficient); - const b = randomInt(options.minConstant, options.maxConstant); - const c = randomInt(options.minSolution, options.maxSolution); - - // Adjust the constant term to ensure that the solution is an integer - const adjustedC = b + a * Math.floor((c - b) / a); - - const x = randomVariable(); - - const bSign = b < 0 ? "-" : "+"; - const absB = Math.abs(b); - - const problem = [ - { type: "text", value: `Solve for ${x}:` }, - { type: "formula", value: `${a}${x} ${bSign} ${absB} = ${adjustedC}` }, - ]; - - const steps = [ - { - type: "text", - value: "Subtract the constant term from both sides of the equation.", - }, - { type: "formula", value: `${a}${x} = ${adjustedC - b}` }, - { - type: "text", - value: - "Divide both sides of the equation by the coefficient of the variable.", - }, - { type: "formula", value: `${x} = \\frac{${adjustedC - b}}{${a}}` }, - { type: "text", value: `Calculate the value of ${x}.` }, - ]; - - // Calculate the solution - const numerator = adjustedC - b; - const denominator = a; - const simplified = math.simplify(`${numerator}/${denominator}`); - - steps.push({ type: "formula", value: `${x} = ${math.format(simplified)}` }); - - const solution = [ - { - type: "numeric", - decimal: math.evaluate(math.format(simplified)), - }, - ]; - - return { - problem, - steps, - solution, - }; -}; - -module.exports = generateProblem; diff --git a/src/problem-generators/math/algebra/linear-equations/withAbsoluteValue.js b/src/problem-generators/math/algebra/linear-equations/withAbsoluteValue.js deleted file mode 100644 index 204d4d5..0000000 --- a/src/problem-generators/math/algebra/linear-equations/withAbsoluteValue.js +++ /dev/null @@ -1,127 +0,0 @@ -/** - * @file src/problem-generators/math/algebra/linear-equations/withAbsoluteValue.js - * @description Generates problems for linear equations with absolute value. In this form, the equation is of the form |ax + b| = c. - */ - -const math = require("mathjs"); -const { randomInt, randomVariable } = require("../../../../utils/randomUtils"); - -/** - * @function generateProblem - Generate a linear equation problem with absolute value. - * @param {Object} options - The options for generating the problem. - * @param {number} options.minCoefficient - The minimum value for the coefficient a. - * @param {number} options.maxCoefficient - The maximum value for the coefficient a. - * @param {number} options.minConstant - The minimum value for the constant b. - * @param {number} options.maxConstant - The maximum value for the constant b. - * @param {number} options.minSolution - The minimum value for the solution c. - * @param {number} options.maxSolution - The maximum value for the solution c. - * @returns {Object} - The linear equation problem with absolute value. - */ -const generateProblem = (options) => { - const a = randomInt(options.minCoefficient, options.maxCoefficient); - const b = randomInt(options.minConstant, options.maxConstant); - const c = randomInt(options.minSolution, options.maxSolution); - - const x = randomVariable(); - - const problem = [ - { type: "text", value: `Solve for ${x}:` }, - { type: "formula", value: `|${a}${x} + ${b}| = ${c}` }, - ]; - - const steps = [ - { - type: "text", - value: "Consider the two cases for the absolute value expression.", - }, - { - type: "text", - value: - "Case 1: The expression inside the absolute value is positive or zero.", - }, - { type: "formula", value: `${a}${x} + ${b} = ${c}` }, - { - type: "text", - value: "Subtract the constant term from both sides of the equation.", - }, - { type: "formula", value: `${a}${x} = ${c - b}` }, - { - type: "text", - value: - "Divide both sides of the equation by the coefficient of the variable.", - }, - { type: "formula", value: `${x} = \\frac{${c - b}}{${a}}` }, - - { - type: "text", - value: "Case 2: The expression inside the absolute value is negative.", - }, - { type: "formula", value: `${a}${x} + ${b} = -${c}` }, - { - type: "text", - value: "Subtract the constant term from both sides of the equation.", - }, - { type: "formula", value: `${a}${x} = -${c} - ${b}` }, - { - type: "text", - value: - "Divide both sides of the equation by the coefficient of the variable.", - }, - { type: "formula", value: `${x} = \\frac{-${c} - ${b}}{${a}}` }, - { type: "text", value: `Calculate the two possible values of ${x}.` }, - ]; - - // Calculate solutions for both cases - const solution1 = math.simplify(`${c - b}/${a}`).toString(); - const solution2 = math.simplify(`(-${c} - ${b})/${a}`).toString(); - const simplifiedFraction1 = math.fraction(c - b, a); - const simplifiedFraction2 = math.fraction(-c - b, a); - const simplifiedString1 = - simplifiedFraction1.d === 1 - ? simplifiedFraction1.n - : `\\frac{${simplifiedFraction1.n}}{${simplifiedFraction1.d}}`; - const simplifiedString2 = - simplifiedFraction2.d === 1 - ? simplifiedFraction2.n - : `\\frac{${simplifiedFraction2.n}}{${simplifiedFraction2.d}}`; - - steps.push( - { type: "formula", value: `${x} = ${simplifiedString1}` }, - { type: "formula", value: `${x} = ${simplifiedString2}` } - ); - - const solution = [ - { - type: "numeric", - decimal: math.evaluate(solution1), - fraction: - simplifiedFraction1.d === 1 - ? null - : { - s: simplifiedFraction1.s, - n: simplifiedFraction1.n, - d: simplifiedFraction1.d, - }, - }, - { - type: "numeric", - decimal: math.evaluate(solution2), - fraction: - simplifiedFraction2.d === 1 - ? null - : { - s: simplifiedFraction2.s, - n: simplifiedFraction2.n, - d: simplifiedFraction2.d, - }, - }, - ]; - - return { - problem, - steps, - solution, - }; -}; - -module.exports = generateProblem; diff --git a/src/problem-generators/math/algebra/linear-equations/withFractions.js b/src/problem-generators/math/algebra/linear-equations/withFractions.js deleted file mode 100644 index 8a672d8..0000000 --- a/src/problem-generators/math/algebra/linear-equations/withFractions.js +++ /dev/null @@ -1,84 +0,0 @@ -/** - * @file src/problem-generators/math/algebra/linear-equations/withFractions.js - * @description Generates problems for linear equations with fractions. In this form, the equation is of the form ax/b = c. - */ - -const math = require("mathjs"); -const { randomInt, randomVariable } = require("../../../../utils/randomUtils"); - -/** - * @function generateProblem - Generate a linear equation problem with fractions. - * @param {Object} options - The options for generating the problem. - * @param {number} options.minCoefficient - The minimum value for the coefficient a. - * @param {number} options.maxCoefficient - The maximum value for the coefficient a. - * @param {number} options.minDenominator - The minimum value for the denominator b. - * @param {number} options.maxDenominator - The maximum value for the denominator b. - * @param {number} options.minSolution - The minimum value for the solution c. - * @param {number} options.maxSolution - The maximum value for the solution c. - * @returns {Object} - The linear equation problem with fractions. - */ -const generateProblem = (options) => { - const a = randomInt(options.minCoefficient, options.maxCoefficient); - const b = randomInt(options.minDenominator, options.maxDenominator); - const c = randomInt(options.minSolution, options.maxSolution); - - const x = randomVariable(); - - const problem = [ - { type: "text", value: `Solve for ${x}:` }, - { type: "formula", value: `\\frac{${a}${x}}{${b}} = ${c}` }, - ]; - - const steps = [ - { - type: "text", - value: "Multiply both sides of the equation by the denominator.", - }, - { type: "formula", value: `${a}${x} = ${b} \\cdot ${c}` }, - { - type: "text", - value: - "Divide both sides of the equation by the coefficient of the variable.", - }, - { type: "formula", value: `${x} = \\frac{${b} \\cdot ${c}}{${a}}` }, - { type: "text", value: `Calculate the value of ${x}.` }, - ]; - - // Calculate the solution - const numerator = b * c; - const denominator = a; - const simplifiedFraction = math.fraction(numerator, denominator); - const simplified = math.simplify(`${numerator}/${denominator}`); - const simplifiedString = - simplifiedFraction.d === 1 - ? simplifiedFraction.n - : `\\frac{${simplifiedFraction.n}}{${simplifiedFraction.d}}`; - - steps.push({ - type: "formula", - value: `${x} = ${simplifiedString}`, - }); - - const solution = [ - { - type: "numeric", - decimal: math.evaluate(math.format(simplified)), - fraction: - simplifiedFraction.d === 1 - ? null - : { - s: simplifiedFraction.s, - n: simplifiedFraction.n, - d: simplifiedFraction.d, - }, - }, - ]; - - return { - problem, - steps, - solution, - }; -}; - -module.exports = generateProblem; diff --git a/src/problem-generators/math/algebra/linear-equations/withParentheses.js b/src/problem-generators/math/algebra/linear-equations/withParentheses.js deleted file mode 100644 index ea10645..0000000 --- a/src/problem-generators/math/algebra/linear-equations/withParentheses.js +++ /dev/null @@ -1,89 +0,0 @@ -/** - * @file src/problem-generators/math/algebra/linear-equations/withParentheses.js - * @description Generates problems for linear equations with parentheses. In this form, the equation is of the form a(x + b) = c. - */ - -const math = require("mathjs"); -const { randomInt, randomVariable } = require("../../../../utils/randomUtils"); - -/** - * @function generateProblem - Generate a linear equation problem with parentheses. - * @param {Object} options - The options for generating the problem. - * @param {number} options.minCoefficient - The minimum value for the coefficient a. - * @param {number} options.maxCoefficient - The maximum value for the coefficient a. - * @param {number} options.minConstant - The minimum value for the constant b. - * @param {number} options.maxConstant - The maximum value for the constant b. - * @param {number} options.minSolution - The minimum value for the solution c. - * @param {number} options.maxSolution - The maximum value for the solution c. - * @returns {Object} - The linear equation problem with parentheses. - */ -const generateProblem = (options) => { - const a = randomInt(options.minCoefficient, options.maxCoefficient); - const b = randomInt(options.minConstant, options.maxConstant); - const c = randomInt(options.minSolution, options.maxSolution); - - const x = randomVariable(); - - const problem = [ - { type: "text", value: `Solve for ${x}:` }, - { type: "formula", value: `${a}(${x} + ${b}) = ${c}` }, - ]; - - const steps = [ - { - type: "text", - value: "Distribute the coefficient a across the parentheses.", - }, - { type: "formula", value: `${a}${x} + ${a * b} = ${c}` }, - { - type: "text", - value: "Subtract the constant term from both sides of the equation.", - }, - { type: "formula", value: `${a}${x} = ${c - a * b}` }, - { - type: "text", - value: - "Divide both sides of the equation by the coefficient of the variable.", - }, - { type: "formula", value: `${x} = \\frac{${c - a * b}}{${a}}` }, - { type: "text", value: `Calculate the value of ${x}.` }, - ]; - - // Calculate the solution - const numerator = c - a * b; - const denominator = a; - const simplifiedFraction = math.fraction(numerator, denominator); - const simplified = math.simplify(`${numerator}/${denominator}`); - const simplifiedString = - simplifiedFraction.d === 1 - ? simplifiedFraction.n - : `\\frac{${simplifiedFraction.n}}{${simplifiedFraction.d}}`; - - steps.push({ - type: "formula", - value: `${x} = ${simplifiedString}`, - }); - - const solution = [ - { - type: "numeric", - decimal: math.evaluate(math.format(simplified)), - fraction: - simplifiedFraction.d === 1 - ? null - : { - s: simplifiedFraction.s, - n: simplifiedFraction.n, - d: simplifiedFraction.d, - }, - }, - ]; - - return { - problem, - steps, - solution, - }; -}; - -module.exports = generateProblem; diff --git a/src/utils/randomUtils.js b/src/utils/randomUtils.js deleted file mode 100644 index dc33335..0000000 --- a/src/utils/randomUtils.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @file src/utils/randomUtils.js - * @description Random utility functions. - */ - -/** - * @function randomInt - Generate a random integer between min and max (inclusive). - * @param {number} min - The minimum value (inclusive). - * @param {number} max - The maximum value (inclusive). - * @returns {number} - A random integer between min and max. - */ -const randomInt = (min, max) => { - return Math.floor(Math.random() * (max - min + 1)) + min; -}; - -/** - * @function randomVariable - Generate a random variable. (a-z) - * @param {boolean} isUpperCase - Whether the variable should be uppercase. (A-Z) - * @returns {string} - A random variable. - */ -const randomVariable = (isUpperCase = false) => { - const min = isUpperCase ? 65 : 97; - const max = isUpperCase ? 90 : 122; - return String.fromCharCode(randomInt(min, max)); -}; - -/** - * @function randomElement - Get a random element from an array. - * @param {Array} array - The array to get a random element from. - * @returns {*} - A random element from the array. - */ -const randomElement = (array) => { - return array[randomInt(0, array.length - 1)]; -}; - -module.exports = { randomInt, randomVariable, randomElement }; diff --git a/tests/controllers/problemController.test.js b/tests/controllers/problemController.test.js index 17a4d13..af5a3cc 100644 --- a/tests/controllers/problemController.test.js +++ b/tests/controllers/problemController.test.js @@ -4,10 +4,11 @@ */ const problemController = require("../../src/controllers/problemController"); -const problemGenerator = require("../../src/problem-generators"); -const index = require("../../src/problem-generators/index.json"); +const ProblemGenerator = require("mpclab"); +const problemGenerator = new ProblemGenerator(); +const index = problemGenerator.index; -jest.mock("../../src/problem-generators"); +jest.mock("mpclab"); describe("ProblemController - getIndex", () => { it("should return the problem generator index successfully", () => { @@ -37,11 +38,11 @@ describe("ProblemController - generateProblem", () => { internalServerError: jest.fn(), }; const generatedProblem = { problem: "generatedProblem" }; - problemGenerator.prototype.generateOne.mockReturnValue(generatedProblem); + ProblemGenerator.prototype.generateOne.mockReturnValue(generatedProblem); problemController.generateProblem(req, res); - expect(problemGenerator.prototype.generateOne).toHaveBeenCalledWith({ + expect(ProblemGenerator.prototype.generateOne).toHaveBeenCalledWith({ path: ["topic1", "topic2"], options: "someOptions", }); @@ -61,7 +62,7 @@ describe("ProblemController - generateProblem", () => { notFound: jest.fn(), internalServerError: jest.fn(), }; - problemGenerator.prototype.generateOne.mockImplementation(() => { + ProblemGenerator.prototype.generateOne.mockImplementation(() => { throw new Error("Generator not found"); }); @@ -83,7 +84,7 @@ describe("ProblemController - generateProblem", () => { notFound: jest.fn(), internalServerError: jest.fn(), }; - problemGenerator.prototype.generateOne.mockImplementation(() => { + ProblemGenerator.prototype.generateOne.mockImplementation(() => { throw new Error("Some other error"); }); diff --git a/tests/controllers/taskController.test.js b/tests/controllers/taskController.test.js index b960c97..ff60c80 100644 --- a/tests/controllers/taskController.test.js +++ b/tests/controllers/taskController.test.js @@ -20,9 +20,9 @@ jest.mock("../../src/services/taskService"); jest.mock("../../src/services/classService"); jest.mock("../../src/utils/validationUtils"); -const ProblemGenerator = require("../../src/problem-generators"); +const ProblemGenerator = require("mpclab"); const problemGenerator = new ProblemGenerator(); -jest.mock("../../src/problem-generators"); +jest.mock("mpclab"); describe("TaskController - createTask", () => { it("should return 400 if class ID is invalid", async () => {