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.
- package/CONTRIBUTING.md +91 -0
- package/README.md +50 -22
- package/client/src/App.jsx +0 -5
- package/client/src/App.scss +6 -0
- package/client/src/ConditionBuilder.scss +34 -1
- package/client/src/ConditionBuilder2.jsx +179 -53
- package/client/src/ContentView.jsx +0 -3
- package/client/src/CronBuilder.jsx +0 -1
- package/client/src/CronPartBuilder.jsx +0 -2
- package/client/src/DashboardView.jsx +0 -5
- package/client/src/DataEditor.jsx +8 -10
- package/client/src/DataImporter.jsx +469 -0
- package/client/src/DataLayout.jsx +0 -1
- package/client/src/DataTable.jsx +2 -368
- package/client/src/DataTable.scss +18 -1
- package/client/src/Field.jsx +85 -48
- package/client/src/FlexBuilder.jsx +1 -1
- package/client/src/ModelCreator.jsx +29 -25
- package/client/src/ModelCreator.scss +13 -0
- package/client/src/ModelCreatorField.jsx +1 -5
- package/client/src/RTE.jsx +1 -6
- package/client/src/RTETrans.jsx +0 -2
- package/client/src/RelationField.jsx +1 -1
- package/client/src/RelationValue.jsx +1 -2
- package/client/src/TourSpotlight.jsx +0 -2
- package/client/src/filter.js +87 -0
- package/client/src/hooks/data.js +1 -3
- package/client/src/hooks/useTutorials.jsx +0 -1
- package/client/src/translations.js +60 -26
- package/package.json +4 -3
- package/server.js +2 -2
- package/src/data.js +8 -0
- package/src/email.js +2 -2
- package/src/engine.js +59 -20
- package/src/index.js +1 -1
- package/src/middlewares/middleware-mongodb.js +0 -1
- package/src/modules/assistant.js +1 -3
- package/src/modules/bucket.js +3 -4
- package/src/modules/data/data.core.js +17 -0
- package/src/modules/{data.js → data/data.js} +4595 -5991
- package/src/modules/data/data.routes.js +1637 -0
- package/src/modules/data/index.js +1 -0
- package/src/modules/file.js +1 -1
- package/src/modules/mongodb.js +0 -1
- package/src/modules/user.js +1 -1
- package/src/modules/workflow.js +38 -38
- package/src/packs.js +4 -1
- package/test/data.backup.integration.test.js +4 -5
- package/test/data.integration.test.js +2 -6
- package/test/events.test.js +1 -1
- package/test/file.test.js +1 -4
- package/test/import_export.integration.test.js +22 -15
- package/test/model.integration.test.js +8 -10
- package/test/user.test.js +2 -2
- package/test/vm.test.js +1 -1
- package/test/workflow.integration.test.js +17 -14
- package/test/workflow.robustness.test.js +15 -10
- package/src/modules/test +0 -147
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './data.js';
|
package/src/modules/file.js
CHANGED
|
@@ -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";
|
package/src/modules/mongodb.js
CHANGED
package/src/modules/user.js
CHANGED
|
@@ -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
|
|
package/src/modules/workflow.js
CHANGED
|
@@ -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
|
|
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
|
-
*
|
|
1472
|
-
*
|
|
1473
|
-
*
|
|
1474
|
-
*
|
|
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 -
|
|
1477
|
-
* @param {object} context -
|
|
1478
|
-
* @param {object} user -
|
|
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.
|
|
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', `
|
|
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
|
-
//
|
|
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]
|
|
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]
|
|
1503
|
+
logger.debug(`[AI Action] Using machine environment API key for ${aiProvider}.`);
|
|
1506
1504
|
}
|
|
1507
1505
|
|
|
1508
1506
|
if (!apiKey) {
|
|
1509
|
-
const message = `
|
|
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.
|
|
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,
|
|
1517
|
+
llm = new ChatOpenAI({ apiKey, model: aiModel, temperature: 0.7 });
|
|
1520
1518
|
break;
|
|
1521
|
-
case '
|
|
1522
|
-
llm = new ChatGoogleGenerativeAI({ apiKey,
|
|
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(`
|
|
1526
|
+
throw new Error(`Unsupported AI provider: ${aiProvider}`);
|
|
1526
1527
|
}
|
|
1527
1528
|
} catch (initError) {
|
|
1528
|
-
const 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.
|
|
1536
|
-
// LangChain
|
|
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.
|
|
1540
|
+
// 4. Create the processing chain (Prompt + Model)
|
|
1540
1541
|
const chain = realPrompt.pipe(llm);
|
|
1541
1542
|
|
|
1542
|
-
// 5.
|
|
1543
|
-
// LangChain
|
|
1544
|
-
logger.debug(`[AI Action]
|
|
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.
|
|
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]
|
|
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 //
|
|
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 = `
|
|
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 '
|
|
13
|
+
} from '../src/index.js';
|
|
14
14
|
|
|
15
15
|
import {
|
|
16
16
|
modelsCollection as getAppModelsCollection,
|
|
17
17
|
getCollectionForUser as getAppUserCollection, getCollectionForUser
|
|
18
|
-
} from '
|
|
18
|
+
} from '../src/modules/mongodb.js';
|
|
19
19
|
import process from "node:process";
|
|
20
20
|
|
|
21
|
-
import { dumpUserData, loadFromDump } from '
|
|
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('
|
|
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 '
|
|
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 '
|
|
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;
|
package/test/events.test.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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 '
|
|
13
|
+
} from '../src/modules/mongodb.js';
|
|
14
14
|
import {sleep} from "data-primals-engine/core";
|
|
15
15
|
import fs from "node:fs";
|
|
16
|
-
import {
|
|
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
|
-
|
|
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", ["
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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,
|
|
3
|
+
import {expect, describe, it, beforeAll} from 'vitest';
|
|
4
4
|
import { Config } from '../src/config.js';
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
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: '
|
|
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
|
|
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 "
|
|
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 "
|
|
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 "
|
|
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 "
|
|
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('
|
|
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
|
-
|
|
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 "
|
|
4
|
-
|
|
5
|
-
import { insertData, editData } from '
|
|
6
|
-
import { modelsCollection as getAppModelsCollection, getCollectionForUser, getCollection } from '
|
|
7
|
-
import * as workflowModule from '
|
|
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('
|
|
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();
|