data-primals-engine 1.2.3 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CONTRIBUTING.md +91 -0
  2. package/README.md +50 -22
  3. package/client/src/App.jsx +0 -5
  4. package/client/src/App.scss +6 -0
  5. package/client/src/ConditionBuilder.scss +34 -1
  6. package/client/src/ConditionBuilder2.jsx +179 -53
  7. package/client/src/ContentView.jsx +0 -3
  8. package/client/src/CronBuilder.jsx +0 -1
  9. package/client/src/CronPartBuilder.jsx +0 -2
  10. package/client/src/DashboardView.jsx +0 -5
  11. package/client/src/DataEditor.jsx +8 -10
  12. package/client/src/DataImporter.jsx +469 -0
  13. package/client/src/DataLayout.jsx +0 -1
  14. package/client/src/DataTable.jsx +2 -368
  15. package/client/src/DataTable.scss +18 -1
  16. package/client/src/Field.jsx +85 -48
  17. package/client/src/FlexBuilder.jsx +1 -1
  18. package/client/src/ModelCreator.jsx +29 -25
  19. package/client/src/ModelCreator.scss +13 -0
  20. package/client/src/ModelCreatorField.jsx +1 -5
  21. package/client/src/RTE.jsx +1 -6
  22. package/client/src/RTETrans.jsx +0 -2
  23. package/client/src/RelationField.jsx +1 -1
  24. package/client/src/RelationValue.jsx +1 -2
  25. package/client/src/TourSpotlight.jsx +0 -2
  26. package/client/src/filter.js +87 -0
  27. package/client/src/hooks/data.js +1 -3
  28. package/client/src/hooks/useTutorials.jsx +0 -1
  29. package/client/src/translations.js +60 -26
  30. package/package.json +4 -3
  31. package/server.js +2 -2
  32. package/src/data.js +8 -0
  33. package/src/email.js +2 -2
  34. package/src/engine.js +59 -20
  35. package/src/index.js +1 -1
  36. package/src/middlewares/middleware-mongodb.js +0 -1
  37. package/src/modules/assistant.js +1 -3
  38. package/src/modules/bucket.js +3 -4
  39. package/src/modules/data/data.core.js +17 -0
  40. package/src/modules/{data.js → data/data.js} +4595 -5991
  41. package/src/modules/data/data.routes.js +1637 -0
  42. package/src/modules/data/index.js +1 -0
  43. package/src/modules/file.js +1 -1
  44. package/src/modules/mongodb.js +0 -1
  45. package/src/modules/user.js +1 -1
  46. package/src/modules/workflow.js +38 -38
  47. package/src/packs.js +4 -1
  48. package/test/data.backup.integration.test.js +4 -5
  49. package/test/data.integration.test.js +2 -6
  50. package/test/events.test.js +1 -1
  51. package/test/file.test.js +1 -4
  52. package/test/import_export.integration.test.js +22 -15
  53. package/test/model.integration.test.js +8 -10
  54. package/test/user.test.js +2 -2
  55. package/test/vm.test.js +1 -1
  56. package/test/workflow.integration.test.js +17 -14
  57. package/test/workflow.robustness.test.js +15 -10
  58. package/src/modules/test +0 -147
@@ -0,0 +1 @@
1
+ export * from './data.js';
@@ -8,7 +8,7 @@ import {getFileExtension, isGUID, uuidv4} from "../core.js";
8
8
  import path from "node:path";
9
9
  import process from "node:process";
10
10
  import fs from "node:fs";
11
- import { checkServerCapacity} from "./data.js";
11
+ import { checkServerCapacity} from "./data/index.js";
12
12
  import crypto from "node:crypto";
13
13
  import * as tar from "tar";
14
14
  import {promisify} from "node:util";
@@ -2,7 +2,6 @@
2
2
  import process from "process";
3
3
  import {Logger} from "../gameObject.js";
4
4
  import {MongoDatabase} from "../engine.js";
5
- import fs from "node:fs";
6
5
 
7
6
  export let modelsCollection, datasCollection, filesCollection, packsCollection;
8
7
 
@@ -3,7 +3,7 @@ import {MongoDatabase} from "../engine.js";
3
3
  import {getCollection, getCollectionForUser, getUserCollectionName} from "./mongodb.js";
4
4
  import {isLocalUser} from "../data.js";
5
5
  import {ObjectId} from "mongodb";
6
- import {getAPILang} from "./data.js";
6
+ import {getAPILang} from "./data/index.js";
7
7
  import {Logger} from "../gameObject.js";
8
8
  import rateLimit from "express-rate-limit";
9
9
 
@@ -1,4 +1,3 @@
1
- // Exemple conceptuel dans la fonction de planification
2
1
  import {getCollection, getCollectionForUser, isObjectId} from "./mongodb.js";
3
2
  import schedule from "node-schedule";
4
3
  import {ObjectId} from "mongodb";
@@ -7,16 +6,16 @@ import crypto from "node:crypto";
7
6
  import ivm from 'isolated-vm';
8
7
 
9
8
  import {Logger} from "../gameObject.js";
10
- import {deleteData, insertData, patchData, searchData} from "./data.js";
11
- import {emailDefaultConfig, maxExecutionsByStep, maxWorkflowSteps, timeoutVM} from "../constants.js";
9
+ import {deleteData, insertData, patchData, searchData} from "./data/index.js";
10
+ import {emailDefaultConfig, maxExecutionsByStep, maxWorkflowSteps} from "../constants.js";
12
11
  import {ChatOpenAI} from "@langchain/openai";
13
12
  import {ChatGoogleGenerativeAI} from "@langchain/google-genai";
14
13
  import {ChatPromptTemplate} from "@langchain/core/prompts";
14
+ import { ChatDeepSeek } from "@langchain/deepseek";
15
15
  import i18n from "../../src/i18n.js";
16
16
  import {sendEmail} from "../email.js";
17
17
 
18
18
  import * as workflowModule from './workflow.js';
19
- import {isConditionMet} from "../filter.js";
20
19
  import util from "node:util";
21
20
 
22
21
  let logger = null;
@@ -1174,7 +1173,6 @@ export async function triggerWorkflows(triggerData, user, eventType) {
1174
1173
 
1175
1174
 
1176
1175
  console.debug(`[Workflow Trigger] Vérification dataFilter pour trigger ${trigger._id} avec filtre combiné:`, JSON.stringify(finalFilter));
1177
- console.log({triggerData, finalFilter});
1178
1176
  const match = await searchData({ model: triggerData._model, filter: finalFilter, limit: 1 }, user);
1179
1177
  if (!match.count) {
1180
1178
  console.debug(`[Workflow Trigger] Trigger ${trigger._id}: dataFilter non satisfait par la donnée ${dataId}. WorkflowRun non créé.`);
@@ -1358,7 +1356,6 @@ export async function processWorkflowRun(workflowRunId, user) {
1358
1356
  if (!isObjectId(actionId)) continue;
1359
1357
  const actionDef = await dbCollection.findOne({ _id: new ObjectId(actionId), _model: 'workflowAction' });
1360
1358
  if (!actionDef) return await logError(`Action definition ${actionId} not found.`);
1361
- console.log({actionDef});
1362
1359
  const actionResult = await workflowModule.executeStepAction(actionDef, contextData, user, dbCollection);
1363
1360
 
1364
1361
  if (actionResult.status === 'paused') {
@@ -1403,7 +1400,7 @@ export async function processWorkflowRun(workflowRunId, user) {
1403
1400
  if (actionResult.updatedContext) {
1404
1401
  contextData = { ...contextData, ...actionResult.updatedContext };
1405
1402
  }
1406
- console.log("action", util.inspect(actionResult, false, 8, true));
1403
+ //console.log("action", util.inspect(actionResult, false, 8, true));
1407
1404
  logger.info(`[processWorkflowRun] Run ID: ${runId}, Step ID: ${currentStepId}, Action ID: ${actionId}: Executed successfully.`);
1408
1405
  }
1409
1406
  }
@@ -1468,104 +1465,107 @@ export async function processWorkflowRun(workflowRunId, user) {
1468
1465
  }
1469
1466
  }
1470
1467
  /**
1471
- * Exécute une action de génération de contenu par IA ('GenerateAIContent').
1472
- * Récupère la clé API (priorité à l'environnement de l'utilisateur), initialise un client LangChain,
1473
- * formate un prompt avec les données du contexte, appelle le LLM, et retourne le résultat
1474
- * pour l'ajouter au contexte du workflow.
1468
+ * Executes an AI content generation action ('GenerateAIContent').
1469
+ * Retrieves the API key (prioritizing the user's environment), initializes a LangChain client,
1470
+ * formats a prompt with context data, calls the LLM, and returns the result
1471
+ * to be added to the workflow context.
1475
1472
  *
1476
- * @param {object} action - La définition de l'action depuis le workflow.
1477
- * @param {object} context - Le contexte d'exécution actuel du workflow.
1478
- * @param {object} user - L'utilisateur qui exécute le workflow.
1473
+ * @param {object} action - The action definition from the workflow.
1474
+ * @param {object} context - The current workflow execution context.
1475
+ * @param {object} user - The user executing the workflow.
1479
1476
  * @returns {Promise<{success: boolean, updatedContext?: object, message?: string}>}
1480
1477
  */
1481
1478
  async function executeGenerateAIContentAction(action, context, user) {
1482
1479
  const { aiProvider, aiModel, prompt } = action;
1483
1480
 
1484
- // 1. Récupérer la clé API (Environnement de l'utilisateur > Environnement de la machine)
1481
+ // 1. Retrieve the API key (User Environment > Machine Environment)
1485
1482
  let apiKey;
1486
1483
 
1487
1484
  const providers = {
1488
1485
  "OpenAI" : "OPENAI_API_KEY",
1489
- "Google": "GOOGLE_API_KEY"
1486
+ "Google": "GOOGLE_API_KEY",
1487
+ "DeepSeek": "DEEPSEEK_API_KEY"
1490
1488
  }
1491
1489
  const envKeyName = providers[aiProvider];
1492
1490
  if( !envKeyName ) {
1493
- return {success: false, message: i18n.t('aiContent.env', `Clé API pour ${aiProvider} (${envKeyName}) non trouvée dans l'environnement de l'utilisateur.`)};
1491
+ return {success: false, message: i18n.t('aiContent.env', `API key for provider ${aiProvider} (${envKeyName}) not found in user environment.`)};
1494
1492
  }
1495
1493
 
1496
- // Cherche d'abord dans les variables d'environnement de l'utilisateur
1494
+ // First look in the user's environment variables
1497
1495
  const envCollection = await getCollectionForUser(user);
1498
1496
  const userEnvVar = await envCollection.findOne({ _model: 'env', name: envKeyName, _user: user.username });
1499
1497
 
1500
1498
  if (userEnvVar && userEnvVar.value) {
1501
1499
  apiKey = userEnvVar.value;
1502
- logger.debug(`[AI Action] Utilisation de la clé API de l'environnement de l'utilisateur pour ${aiProvider}.`);
1500
+ logger.debug(`[AI Action] Using user environment API key for ${aiProvider}.`);
1503
1501
  } else {
1504
1502
  apiKey = process.env[envKeyName];
1505
- logger.debug(`[AI Action] Utilisation de la clé API de l'environnement de la machine pour ${aiProvider}.`);
1503
+ logger.debug(`[AI Action] Using machine environment API key for ${aiProvider}.`);
1506
1504
  }
1507
1505
 
1508
1506
  if (!apiKey) {
1509
- const message = `Clé API pour ${aiProvider} (${envKeyName}) non trouvée dans l'environnement de l'utilisateur ou de la machine.`;
1507
+ const message = `API key for ${aiProvider} (${envKeyName}) not found in user or machine environment.`;
1510
1508
  logger.error(`[AI Action] ${message}`);
1511
1509
  return { success: false, message };
1512
1510
  }
1513
1511
 
1514
- // 2. Initialiser le client LLM avec LangChain
1512
+ // 2. Initialize the LLM client with LangChain
1515
1513
  let llm;
1516
1514
  try {
1517
1515
  switch (aiProvider) {
1518
1516
  case 'OpenAI':
1519
- llm = new ChatOpenAI({ apiKey, modelName: aiModel, temperature: 0.7 });
1517
+ llm = new ChatOpenAI({ apiKey, model: aiModel, temperature: 0.7 });
1520
1518
  break;
1521
- case 'GoogleGemini':
1522
- llm = new ChatGoogleGenerativeAI({ apiKey, modelName: aiModel, temperature: 0.7 });
1519
+ case 'Google':
1520
+ llm = new ChatGoogleGenerativeAI({ apiKey, model: aiModel, temperature: 0.7 });
1521
+ break;
1522
+ case 'DeepSeek':
1523
+ llm = new ChatDeepSeek({ apiKey, model: aiModel, temperature: 0.7 });
1523
1524
  break;
1524
1525
  default:
1525
- throw new Error(`Fournisseur IA non supporté : ${aiProvider}`);
1526
+ throw new Error(`Unsupported AI provider: ${aiProvider}`);
1526
1527
  }
1527
1528
  } catch (initError) {
1528
- const message = `Échec de l'initialisation du client IA pour ${aiProvider}: ${initError.message}`;
1529
+ const message = `Failed to initialize AI client for ${aiProvider}: ${initError.message}`;
1529
1530
  logger.error(`[AI Action] ${message}`);
1530
1531
  return { success: false, message };
1531
1532
  }
1532
1533
 
1533
1534
  try {
1534
1535
  const substitutedPrompt = await substituteVariables(prompt, context, user);
1535
- // 3. Créer le "Prompt Template"
1536
- // LangChain gère la substitution des variables comme {triggerData.name}
1536
+ // 3. Create the "Prompt Template"
1537
+ // LangChain handles variable substitution like {triggerData.name}
1537
1538
  const realPrompt = ChatPromptTemplate.fromTemplate(substitutedPrompt);
1538
1539
 
1539
- // 4. Créer la chaîne de traitement (Prompt + Modèle)
1540
+ // 4. Create the processing chain (Prompt + Model)
1540
1541
  const chain = realPrompt.pipe(llm);
1541
1542
 
1542
- // 5. Invoquer la chaîne avec le contexte complet
1543
- // LangChain remplacera automatiquement les placeholders dans le prompt.
1544
- logger.debug(`[AI Action] Invocation de l'IA avec le modèle ${aiModel}.`);
1543
+ // 5. Invoke the chain with the complete context
1544
+ // LangChain will automatically replace placeholders in the prompt.
1545
+ logger.debug(`[AI Action] Invoking AI with model ${aiModel}.`);
1545
1546
  const response = await chain.invoke(context);
1546
1547
 
1547
- // 6. Préparer le résultat pour le fusionner dans le contexte du workflow
1548
+ // 6. Prepare the result to be merged into the workflow context
1548
1549
  const llmOutput = response.content;
1549
1550
  const outputVariable = 'aiContent';
1550
1551
  const updatedContext = {
1551
1552
  [outputVariable]: llmOutput
1552
1553
  };
1553
1554
 
1554
- logger.info(`[AI Action] Contenu généré avec succès et stocké dans la variable de contexte '${outputVariable}'.`);
1555
+ logger.info(`[AI Action] Content generated successfully and stored in context variable '${outputVariable}'.`);
1555
1556
 
1556
1557
  return {
1557
1558
  success: true,
1558
- updatedContext // Cet objet sera fusionné au contexte principal par le moteur de workflow
1559
+ updatedContext // This object will be merged into the main context by the workflow engine
1559
1560
  };
1560
1561
 
1561
1562
  } catch (llmError) {
1562
- const message = `Erreur durant la génération de contenu IA avec ${aiProvider}: ${llmError.message}`;
1563
+ const message = `Error during AI content generation with ${aiProvider}: ${llmError.message}`;
1563
1564
  logger.error(`[AI Action] ${message}`, llmError.stack);
1564
1565
  return { success: false, message };
1565
1566
  }
1566
1567
  }
1567
1568
 
1568
-
1569
1569
  /**
1570
1570
  * Gère l'action d'envoi d'e-mail d'un workflow.
1571
1571
  * Cette version améliorée peut traiter une liste de destinataires, en envoyant un e-mail
package/src/packs.js CHANGED
@@ -1,4 +1,4 @@
1
- import {getModels} from "./modules/data.js";
1
+ import {getModels} from "./modules/data/index.js";
2
2
 
3
3
 
4
4
  /*
@@ -1360,6 +1360,9 @@ return { processedChunk: context.result.chunk };
1360
1360
  },{
1361
1361
  name: "GOOGLE_API_KEY",
1362
1362
  value: "demo"
1363
+ },{
1364
+ name: "DEEPSEEK_API_KEY",
1365
+ value: "demo"
1363
1366
  }]
1364
1367
  }
1365
1368
  }
@@ -10,20 +10,19 @@ import { vi } from 'vitest'
10
10
  import {
11
11
  createModel,
12
12
  insertData
13
- } from 'data-primals-engine/modules/data';
13
+ } from '../src/index.js';
14
14
 
15
15
  import {
16
16
  modelsCollection as getAppModelsCollection,
17
17
  getCollectionForUser as getAppUserCollection, getCollectionForUser
18
- } from 'data-primals-engine/modules/mongodb';
18
+ } from '../src/modules/mongodb.js';
19
19
  import process from "node:process";
20
20
 
21
- import { dumpUserData, loadFromDump } from 'data-primals-engine/modules/data';
21
+ import { dumpUserData, loadFromDump } from '../src/index.js';
22
22
  import fs from "node:fs";
23
23
  import {initEngine} from "../src/setenv.js";
24
- import {getUserCollectionName} from "../src/modules/mongodb.js";
25
24
 
26
- vi.mock('data-primals-engine/engine', async(importOriginal) => {
25
+ vi.mock('../src/engine', async(importOriginal) => {
27
26
  const mod = await importOriginal() // type is inferred
28
27
  return {
29
28
  ...mod
@@ -7,19 +7,15 @@ import {
7
7
  editData,
8
8
  deleteData,
9
9
  searchData, installPack, deleteModels, createModel, patchData
10
- } from 'data-primals-engine/modules/data';
10
+ } from '../src/index.js';
11
11
 
12
12
  import {
13
13
  modelsCollection as getAppModelsCollection,
14
14
  getCollection,
15
15
  getCollectionForUser as getAppUserCollection, getCollectionForUser
16
- } from 'data-primals-engine/modules/mongodb';
16
+ } from '../src/modules/mongodb.js';
17
17
  import {getRandom} from "../src/core.js";
18
18
  import {generateUniqueName, initEngine} from "../src/setenv.js";
19
- import {processWorkflowRun} from "data-primals-engine/modules/workflow";
20
- import {sendEmail} from "../src/email.js";
21
- import {MongoDatabase} from "../src/engine.js";
22
- import {getUserCollectionName} from "../src/modules/mongodb.js";
23
19
 
24
20
  let testModelsColInstance;
25
21
  let testDatasColInstance;
@@ -1,7 +1,7 @@
1
1
  // events.test.js
2
2
  import { Event } from '../src/events.js';
3
3
  import {vitest} from "vitest";
4
- import {expect, describe, it, beforeEach, beforeAll, afterAll} from 'vitest';
4
+ import {expect, describe, it, beforeEach} from 'vitest';
5
5
 
6
6
  describe('Event System', () => {
7
7
  beforeEach(() => {
package/test/file.test.js CHANGED
@@ -1,16 +1,13 @@
1
- // __tests__/file.integration.test.js
2
- import { expect, describe, it, beforeEach, afterEach, beforeAll, afterAll, vi } from 'vitest';
1
+ import { expect, describe, it, beforeEach, beforeAll, afterAll, vi } from 'vitest';
3
2
  import { Config } from '../src/config.js';
4
3
  import fs from 'node:fs';
5
4
  import path from 'node:path';
6
5
  import { fileURLToPath } from 'node:url';
7
- import { ObjectId } from 'mongodb';
8
6
  import { initEngine, generateUniqueName } from "../src/setenv.js";
9
7
  import { addFile, removeFile, getFile, onInit } from "../src/modules/file.js";
10
8
  import {getCollection, getUserCollectionName} from "../src/modules/mongodb.js";
11
9
  import { Logger } from "../src/gameObject.js";
12
10
  import {maxPrivateFileSize} from "../src/constants.js";
13
- import {getCollectionForUser} from "data-primals-engine/modules/mongodb";
14
11
 
15
12
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
16
13
 
@@ -1,4 +1,4 @@
1
- import {expect, describe, it, beforeEach, beforeAll, afterAll, vi} from 'vitest';
1
+ import {expect, describe, it, beforeEach, beforeAll, afterAll, vi, afterEach} from 'vitest';
2
2
 
3
3
  // --- Importations des modules de votre application ---
4
4
  import {
@@ -10,12 +10,11 @@ import {
10
10
  import {
11
11
  modelsCollection as getAppModelsCollection,
12
12
  getCollectionForUser as getAppUserCollection, getCollectionForUser
13
- } from 'data-primals-engine/modules/mongodb';
13
+ } from '../src/modules/mongodb.js';
14
14
  import {sleep} from "data-primals-engine/core";
15
15
  import fs from "node:fs";
16
- import {getUniquePort, initEngine} from "../src/setenv.js";
16
+ import {initEngine} from "../src/setenv.js";
17
17
  import {Config} from "../src/index.js";
18
- import {ObjectId} from "mongodb";
19
18
 
20
19
  // --- Données Mock ---
21
20
  const mockUser = {
@@ -38,13 +37,9 @@ const impexTestModel = {
38
37
  };
39
38
 
40
39
  // --- Setup de l'environnement de test ---
41
- let mongod;
42
- let testDbUri;
43
- const testDbName = 'testIntegrationDbHO_Impex';
44
40
  let testModelsColInstance;
45
41
  let testDatasColInstance;
46
- let engineInstance;
47
- const port = getUniquePort(); // Port unique pour cette suite de tests
42
+
48
43
  function blobToFile(theBlob, fileName){
49
44
  //A Blob() is almost a File() - it's just missing the two properties below which we will add
50
45
  theBlob.lastModifiedDate = new Date();
@@ -53,9 +48,20 @@ function blobToFile(theBlob, fileName){
53
48
  }
54
49
 
55
50
  beforeAll(async () =>{
56
- Config.Set("modules", ["mongodb", "data", "file", "bucket", "workflow","user", "assistant"]);
51
+ Config.Set("modules", ["data", "mongodb", "file", "bucket", "workflow","user", "assistant"]);
57
52
  await initEngine();
58
53
  })
54
+
55
+ beforeEach(async() =>{
56
+ // tell vitest we use mocked time
57
+ vi.useFakeTimers({ shouldAdvanceTime: true })
58
+ })
59
+
60
+ afterEach(() => {
61
+ vi.runOnlyPendingTimers();
62
+ // restoring date after each test run
63
+ vi.useRealTimers()
64
+ })
59
65
  afterAll(async () => {
60
66
  const coll = await getCollectionForUser(mockUser);
61
67
  await coll.drop();
@@ -84,6 +90,7 @@ describe('Intégration des fonctions d\'Import/Export', () => {
84
90
 
85
91
  describe('Export de données', () => {
86
92
  it('devrait exporter les données en format JSON', async () => {
93
+
87
94
  const res= await exportData({
88
95
  models: [impexTestModel.name],
89
96
  depth: 1
@@ -107,6 +114,7 @@ describe('Intégration des fonctions d\'Import/Export', () => {
107
114
 
108
115
  describe('Import de données', () => {
109
116
  it('devrait importer des données depuis une chaîne JSON', async () => {
117
+
110
118
  const jsonDataToImport = [
111
119
  { name: 'Produit D', sku: 'SKU-D', price: 1.00, inStock: true },
112
120
  { name: 'Produit E', sku: 'SKU-E', price: 2.00 } // inStock utilisera la valeur par défaut
@@ -124,7 +132,7 @@ describe('Intégration des fonctions d\'Import/Export', () => {
124
132
  expect(result.success).toBe(true);
125
133
  expect(result.job.jobId).not.toBeNull();
126
134
 
127
- await sleep(8000)
135
+ await sleep(5000);
128
136
 
129
137
  // Vérification directe en base de données
130
138
  const importedDocs = await testDatasColInstance.find({
@@ -158,7 +166,7 @@ describe('Intégration des fonctions d\'Import/Export', () => {
158
166
  expect(result.success).toBe(true);
159
167
  expect(result.job.jobId).not.toBeNull();
160
168
 
161
- await sleep(8000);
169
+ await sleep(5000);
162
170
  // Vérification en base de données
163
171
  const importedDocs = await testDatasColInstance.find({
164
172
  _model: impexTestModel.name,
@@ -183,7 +191,7 @@ Valide J,SKU-J,,false
183
191
  Valide K,SKU-A,40,true`;
184
192
 
185
193
  // Exécution de la fonction d'import (hypothétique)x
186
- var blob = new Blob([csvStringToImport], {type: "text/csv"});
194
+ const blob = new Blob([csvStringToImport], {type: "text/csv"});
187
195
  fs.writeFileSync('test.csv', csvStringToImport);
188
196
  blob.path = 'test.csv';
189
197
  blob.originalFilename = 'test.csv';
@@ -194,8 +202,7 @@ Valide K,SKU-A,40,true`;
194
202
  expect(result.success).toBe(true);
195
203
  expect(result.job.jobId).not.toBeNull();
196
204
 
197
- await sleep(8000);
198
-
205
+ await sleep(5000);
199
206
  // Vérifier que seule les données valides sont en BDD
200
207
  const count = await testDatasColInstance.countDocuments({ _model: impexTestModel.name, sku: 'SKU-H' });
201
208
  expect(count).toBe(1); // Seule la ligne valide 'SKU-H' doit être insérée.
@@ -1,19 +1,17 @@
1
1
  // __tests__/data.integration.test.js
2
2
  import { ObjectId } from 'mongodb';
3
- import {expect, describe, it, beforeEach, afterEach, beforeAll, afterAll, vi} from 'vitest';
3
+ import {expect, describe, it, beforeAll} from 'vitest';
4
4
  import { Config } from '../src/config.js';
5
5
 
6
6
  import {
7
- modelsCollection as getAppModelsCollection,
8
- datasCollection, getCollection // Accès direct pour vérifications
9
- } from 'data-primals-engine/modules/mongodb';
10
- import {generateUniqueName, getUniquePort, initEngine} from "../src/setenv.js";
11
- import {editModel} from "../src/modules/data.js";
12
- import {getCollectionForUser, getUserCollectionName} from "../src/modules/mongodb.js";
7
+ getCollection // Accès direct pour vérifications
8
+ } from '../src/modules/mongodb.js';
9
+ import {generateUniqueName, initEngine} from "../src/setenv.js";
10
+ import {editModel} from "../src/index.js";
11
+ import {getCollectionForUser} from "../src/modules/mongodb.js";
13
12
 
14
13
  let testModelsColInstance;
15
14
  let testModelId;
16
- let lastUser;
17
15
  // Cette fonction va remplacer la logique de votre beforeEach pour la création de contexte
18
16
  async function setupTestContext() {
19
17
 
@@ -24,7 +22,7 @@ async function setupTestContext() {
24
22
  // Créer un utilisateur unique pour ce test
25
23
  const currentTestUser = {
26
24
  username: generateUniqueName('testuserModelIntegration'),
27
- userPlan: 'premium',
25
+ userPlan: 'free',
28
26
  email: generateUniqueName('test') + '@example.com'
29
27
  };
30
28
 
@@ -125,7 +123,7 @@ describe('CRUD on model definitions and integrity tests', () => {
125
123
 
126
124
  describe('editModel unit tests', () => {
127
125
 
128
- it.skip('should create and drop index when field.index is toggled (premium user)', async () => {
126
+ it('should create and drop index when field.index is toggled (premium user)', async () => {
129
127
  // --- SETUP ---
130
128
  const { coll, currentTestUser, comprehensiveTestModelDefinition } = await setupTestContext();
131
129
  const fieldToIndex = 'stringUnique'; // Utiliser un champ qui existe vraiment dans le modèle
package/test/user.test.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { expect, describe, it, beforeEach, beforeAll, afterAll } from 'vitest';
2
2
  import { hasPermission, getUserActivePermissions } from '../src/modules/user.js';
3
- import {initEngine} from "data-primals-engine/setenv";
3
+ import {initEngine} from "../src/setenv";
4
4
  import {generateUniqueName} from "../src/setenv.js";
5
5
  import {
6
6
  getCollectionForUser as getAppUserCollection,
7
7
  modelsCollection as getAppModelsCollection
8
- } from "data-primals-engine/modules/mongodb";
8
+ } from "../src/modules/mongodb.js";
9
9
  import {Config} from "../src/index.js";
10
10
  let permRead, permWrite, permDelete, permManage;
11
11
  let roleEditor;
package/test/vm.test.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {expect, describe, it, beforeEach, afterEach, beforeAll, afterAll, vi, vitest} from 'vitest';
2
2
  import ivm from "isolated-vm";
3
- import {sleep} from "data-primals-engine/core";
3
+ import {sleep} from "../src/core";
4
4
 
5
5
  vi.stubEnv('ENCRYPTION_KEY', '12345678901234567890123456789012');
6
6
 
@@ -1,20 +1,16 @@
1
- // __tests__/workflow.integration.test.js
2
1
  import { expect, describe, it, beforeEach,afterEach, beforeAll, afterAll, vi } from 'vitest';
3
- import { Config } from "data-primals-engine/config";
4
-
5
- import {insertData, editData, deleteData, patchData} from 'data-primals-engine/modules/data';
6
- import { modelsCollection as getAppModelsCollection, getCollectionForUser } from 'data-primals-engine/modules/mongodb';
7
- import * as workflowModule from 'data-primals-engine/modules/workflow';
8
- import {getUniquePort, initEngine} from "../src/setenv.js";
9
- import process from "process";
10
- import {getUserCollectionName} from "../src/modules/mongodb.js";
2
+ import { Config } from "../src/config";
11
3
 
4
+ import {insertData, editData, deleteData, patchData} from '../src/index.js';
5
+ import { modelsCollection as getAppModelsCollection, getCollectionForUser } from '../src/modules/mongodb.js';
6
+ import * as workflowModule from '../src/modules/workflow.js';
7
+ import {initEngine} from "../src/setenv.js";
12
8
 
13
9
  beforeAll(async () =>{
14
10
  Config.Set("modules", ["mongodb", "data", "file", "bucket", "workflow","user", "assistant"]);
15
11
  await initEngine();
16
12
  })
17
- vi.mock('data-primals-engine/modules/workflow', { spy: true })
13
+ vi.mock('../src/modules/workflow.js', { spy: true })
18
14
  // --- Données Mock pour les tests ---
19
15
  const mockUser = {
20
16
  username: 'testuserWorkflow',
@@ -139,8 +135,6 @@ const processWorkflowRunSpy = vi.spyOn(workflowModule, 'processWorkflowRun');
139
135
  beforeEach(async () => {
140
136
  testModelsColInstance = getAppModelsCollection;
141
137
  testDatasColInstance = await getCollectionForUser(mockUser);
142
- // Nettoyer les données avant chaque test
143
- await testDatasColInstance.deleteMany({_user: "testuserWorkflow"});
144
138
 
145
139
  // Réinitialiser l'espion
146
140
  processWorkflowRunSpy.mockClear();
@@ -153,9 +147,15 @@ beforeEach(async () => {
153
147
  ...workflowMetaModels.map(m => ({...m})) // Copie pour éviter les mutations
154
148
  ]);
155
149
  }
156
- console.log({mods})
157
- });
150
+ // tell vitest we use mocked time
151
+ vi.useFakeTimers({ shouldAdvanceTime: true })
152
+ })
158
153
 
154
+ afterEach(() => {
155
+ vi.runOnlyPendingTimers();
156
+ // restoring date after each test run
157
+ vi.useRealTimers()
158
+ })
159
159
  afterAll(async () => {
160
160
  const coll = await getCollectionForUser(mockUser);
161
161
  await coll.drop();
@@ -167,6 +167,9 @@ describe('Intégration des Workflows - triggerWorkflows', () => {
167
167
 
168
168
  // Avant chaque test de ce bloc, on crée un workflow et une étape de base
169
169
  const initTest = async () => {
170
+ // Nettoyer les données avant chaque test
171
+ await testDatasColInstance.deleteMany({_user: "testuserWorkflow"});
172
+
170
173
  const workflowInsertResult = await insertData('workflow', { name: 'Test Workflow' }, {}, mockUser, false);
171
174
  testWorkflow = { _id: workflowInsertResult.insertedIds[0] };
172
175
 
@@ -1,15 +1,14 @@
1
1
  import { ObjectId } from 'mongodb';
2
- import {expect, describe, it, beforeEach, beforeAll, vi, afterAll} from 'vitest';
3
- import { Config } from "data-primals-engine/config";
4
- // --- Importations des modules de l'application ---
5
- import { insertData, editData } from 'data-primals-engine/modules/data';
6
- import { modelsCollection as getAppModelsCollection, getCollectionForUser, getCollection } from 'data-primals-engine/modules/mongodb';
7
- import * as workflowModule from 'data-primals-engine/modules/workflow';
2
+ import {expect, describe, it, beforeEach, beforeAll, vi, afterAll, afterEach} from 'vitest';
3
+ import { Config } from "../src/config";
4
+
5
+ import { insertData, editData } from '../src/index.js';
6
+ import { modelsCollection as getAppModelsCollection, getCollectionForUser, getCollection } from '../src/modules/mongodb.js';
7
+ import * as workflowModule from '../src/modules/workflow.js';
8
8
  import {initEngine} from "../src/setenv.js";
9
9
  import {maxExecutionsByStep} from "../src/constants.js";
10
- import {getUserCollectionName} from "../src/modules/mongodb.js";
11
10
 
12
- vi.mock('data-primals-engine/modules/workflow', { spy: true })
11
+ vi.mock('../src/modules/workflow.js', { spy: true })
13
12
 
14
13
  const mockUser = {
15
14
  username: 'robustnessUser',
@@ -42,12 +41,18 @@ beforeEach(async () => {
42
41
  await testDatasColInstance.deleteMany({ _user: mockUser.username });
43
42
  await getCollection('job_locks').deleteMany({}); // Nettoyer les verrous
44
43
  const mods = await testModelsColInstance.find({ $and: [{_user: mockUser.username}, {$or: [{name: targetDataModel.name}, ...workflowMetaModels.map(m =>({name: m.name}))] }]}).toArray();
45
- console.log({mods})
46
44
  if( mods.length === 0){
47
45
  await testModelsColInstance.insertMany([targetDataModel, ...workflowMetaModels]);
48
46
  }
49
- });
47
+ // tell vitest we use mocked time
48
+ vi.useFakeTimers({ shouldAdvanceTime: true })
49
+ })
50
50
 
51
+ afterEach(() => {
52
+ vi.runOnlyPendingTimers();
53
+ // restoring date after each test run
54
+ vi.useRealTimers()
55
+ })
51
56
  afterAll(async () => {
52
57
  const coll = await getCollectionForUser(mockUser);
53
58
  await coll.drop();