data-primals-engine 1.2.1 → 1.2.3

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.
@@ -0,0 +1,193 @@
1
+ // __tests__/file.integration.test.js
2
+ import { expect, describe, it, beforeEach, afterEach, beforeAll, afterAll, vi } from 'vitest';
3
+ import { Config } from '../src/config.js';
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { ObjectId } from 'mongodb';
8
+ import { initEngine, generateUniqueName } from "../src/setenv.js";
9
+ import { addFile, removeFile, getFile, onInit } from "../src/modules/file.js";
10
+ import {getCollection, getUserCollectionName} from "../src/modules/mongodb.js";
11
+ import { Logger } from "../src/gameObject.js";
12
+ import {maxPrivateFileSize} from "../src/constants.js";
13
+ import {getCollectionForUser} from "data-primals-engine/modules/mongodb";
14
+
15
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
16
+
17
+ vi.stubEnv('ENCRYPTION_KEY', '12345678901234567890123456789012');
18
+
19
+ // Mock pour les fichiers uploadés
20
+ const createMockFile = (name, size, type = 'text/plain') => {
21
+ const tempPath = path.join(__dirname, 'temp', name);
22
+ fs.writeFileSync(tempPath, 'a'.repeat(size));
23
+ return {
24
+ name,
25
+ size,
26
+ type,
27
+ path: tempPath
28
+ };
29
+ };
30
+ let engine;
31
+ const testUploadDir = path.join(process.cwd(), "uploads", "private");
32
+ const testTempDir = path.join(__dirname, 'temp');
33
+ let filesCollection;
34
+
35
+ beforeAll(async () => {
36
+ Config.Set("modules", ["mongodb", "data", "file", "bucket", "user","file"]);
37
+ engine= await initEngine();
38
+ await onInit(engine);
39
+
40
+ // Créer les répertoires nécessaires
41
+ if (!fs.existsSync(testUploadDir)) {
42
+ fs.mkdirSync(testUploadDir, { recursive: true });
43
+ }
44
+ if (!fs.existsSync(testTempDir)) {
45
+ fs.mkdirSync(testTempDir, { recursive: true });
46
+ }
47
+
48
+ filesCollection = await getCollection("files");
49
+ });
50
+ let testUser = {
51
+ username: generateUniqueName('testuser'),
52
+ _user: generateUniqueName('testuser'),
53
+ userPlan: 'premium',
54
+ permissions: ['API_UPLOAD_FILE']
55
+ };
56
+
57
+ describe('File Module Integration Tests', () => {
58
+
59
+ beforeEach(async () => {
60
+ // Créer un utilisateur de test
61
+ // Nettoyer les collections avant chaque test
62
+ await filesCollection.deleteMany({});
63
+
64
+ // Nettoyer le répertoire upload
65
+ const files = fs.readdirSync(testUploadDir);
66
+ for (const file of files) {
67
+ fs.unlinkSync(path.join(testUploadDir, file));
68
+ }
69
+ });
70
+
71
+ afterAll(async () => {
72
+ // Nettoyer après tous les tests
73
+ await filesCollection.deleteMany({});
74
+ if (fs.existsSync(testUploadDir)) {
75
+ fs.rmSync(testUploadDir, { recursive: true });
76
+ }
77
+ if (fs.existsSync(testTempDir)) {
78
+ fs.rmSync(testTempDir, { recursive: true });
79
+ }
80
+ });
81
+
82
+ describe('addFile', () => {
83
+ it('should successfully add a file with local storage', async () => {
84
+ const mockFile = createMockFile('test.txt', 1024); // 1KB file
85
+
86
+ const guid = await addFile(mockFile, testUser);
87
+
88
+ // Vérifier le retour
89
+ expect(guid).toBeDefined();
90
+ expect(guid).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i);
91
+
92
+ // Vérifier en base de données
93
+ const fileRecord = await filesCollection.findOne({ guid });
94
+ expect(fileRecord).toBeDefined();
95
+ expect(fileRecord.filename).toBeDefined();
96
+ expect(fileRecord.size).toBe(1024);
97
+ expect(fileRecord.user).toBe(testUser.username);
98
+ expect(fileRecord.storage).toBe('local');
99
+
100
+ // Vérifier que le fichier existe physiquement
101
+ const expectedPath = path.join(testUploadDir, `${guid}.txt`);
102
+ expect(fs.existsSync(expectedPath)).toBe(true);
103
+ });
104
+
105
+ it('should throw error when file size exceeds limit', async () => {
106
+ const mockFile = createMockFile('large.txt', maxPrivateFileSize+1); // 11MB (dépasse la limite de 10MB)
107
+
108
+ await expect(addFile(mockFile, testUser)).rejects.toThrow(/La taille du fichier dépasse la limite autorisée/);
109
+ });
110
+
111
+ it.skip('should throw error when storage limit exceeded', async ({skip}) => {
112
+ // Mock la fonction de calcul d'usage pour simuler un dépassement
113
+ vi.spyOn(engine.userProvider, 'getUserStorageLimit').mockResolvedValue(85 * 1024 * 1024); // 5MB
114
+
115
+ const mockFile = createMockFile('test.txt', 1024 * 1024); // 1MB
116
+
117
+ await expect(addFile(mockFile, testUser)).rejects.toThrow("api.data.storageLimitExceeded");
118
+ });
119
+
120
+ it.skip('should throw error when server capacity is insufficient', async ({skip}) => {
121
+ // Mock la vérification de capacité serveur
122
+ vi.spyOn(engine.userProvider, 'checkServerCapacity').mockResolvedValue({ isSufficient: false });
123
+
124
+ const mockFile = createMockFile('test.txt', 1024);
125
+
126
+ await expect(addFile(mockFile, testUser)).rejects.toThrow("api.data.serverStorageFull");
127
+ });
128
+ });
129
+
130
+ describe('removeFile', () => {
131
+ it('should successfully remove a locally stored file', async () => {
132
+ // D'abord ajouter un fichier
133
+ const mockFile = createMockFile('to-delete.txt', 1024);
134
+ const guid = await addFile(mockFile, testUser);
135
+
136
+ // Vérifier qu'il existe avant suppression
137
+ const beforeDelete = await getFile(guid);
138
+ expect(beforeDelete).toBeDefined();
139
+
140
+ // Supprimer le fichier
141
+ await removeFile(guid, testUser);
142
+
143
+ // Vérifier en base de données
144
+ const afterDelete = await getFile(guid);
145
+ expect(afterDelete).toBeNull();
146
+
147
+ // Vérifier que le fichier physique a été supprimé
148
+ const expectedPath = path.join(testUploadDir, `${guid}.txt`);
149
+ expect(fs.existsSync(expectedPath)).toBe(false);
150
+ });
151
+
152
+ it('should handle trying to remove non-existent file gracefully', async () => {
153
+ const nonExistentGuid = '123e4567-e89b-12d3-a456-426614174000';
154
+
155
+ vi.spyOn(engine.getComponent(Logger), "info");
156
+
157
+ // Cela ne devrait pas throw d'erreur
158
+ await removeFile(nonExistentGuid, testUser);
159
+
160
+ // Vérifier que le logger a bien enregistré l'info
161
+ expect(engine.getComponent(Logger).info).toHaveBeenCalledWith(
162
+ expect.stringContaining(`Tentative de suppression d'un fichier inexistant`),
163
+ 'warn'
164
+ );
165
+ });
166
+
167
+ it('should throw error when GUID is invalid', async () => {
168
+ await expect(removeFile('invalid-guid', testUser)).rejects.toThrow("Le GUID du fichier n'est pas valide.");
169
+ });
170
+ });
171
+
172
+ describe('getFile', () => {
173
+ it('should retrieve file metadata', async () => {
174
+ const mockFile = createMockFile('metadata-test.txt', 2048);
175
+ const guid = await addFile(mockFile, testUser);
176
+
177
+ const fileData = await getFile(guid);
178
+
179
+ expect(fileData).toBeDefined();
180
+ expect(fileData.guid).toBe(guid);
181
+ expect(fileData.filename).toContain('.txt');
182
+ expect(fileData.size).toBe(2048);
183
+ expect(fileData.user).toBe(testUser.username);
184
+ });
185
+
186
+ it('should return null for non-existent file', async () => {
187
+ const nonExistentGuid = '123e4567-e89b-12d3-a456-426614174000';
188
+ const fileData = await getFile(nonExistentGuid);
189
+
190
+ expect(fileData).toBeNull();
191
+ });
192
+ });
193
+ });
@@ -2,20 +2,20 @@ import {expect, describe, it, beforeEach, beforeAll, afterAll, vi} from 'vitest'
2
2
 
3
3
  // --- Importations des modules de votre application ---
4
4
  import {
5
- createModel,
6
5
  insertData,
7
6
  exportData,
8
7
  importData
9
- } from 'data-primals-engine/modules/data';
8
+ } from '../src/index.js';
10
9
 
11
10
  import {
12
11
  modelsCollection as getAppModelsCollection,
13
- getCollectionForUser as getAppUserCollection
12
+ getCollectionForUser as getAppUserCollection, getCollectionForUser
14
13
  } from 'data-primals-engine/modules/mongodb';
15
14
  import {sleep} from "data-primals-engine/core";
16
15
  import fs from "node:fs";
17
16
  import {getUniquePort, initEngine} from "../src/setenv.js";
18
17
  import {Config} from "../src/index.js";
18
+ import {ObjectId} from "mongodb";
19
19
 
20
20
  // --- Données Mock ---
21
21
  const mockUser = {
@@ -56,6 +56,10 @@ beforeAll(async () =>{
56
56
  Config.Set("modules", ["mongodb", "data", "file", "bucket", "workflow","user", "assistant"]);
57
57
  await initEngine();
58
58
  })
59
+ afterAll(async () => {
60
+ const coll = await getCollectionForUser(mockUser);
61
+ await coll.drop();
62
+ })
59
63
  // --- Début des tests ---
60
64
  describe('Intégration des fonctions d\'Import/Export', () => {
61
65
 
@@ -114,13 +118,13 @@ describe('Intégration des fonctions d\'Import/Export', () => {
114
118
  fs.writeFileSync('test.json', jsonString);
115
119
  blob.path = 'test.json';
116
120
  blob.originalFilename = 'test.json';
117
- const result = await importData({model: impexTestModel.name}, {file: blobToFile(blob,"test.json")}, mockUser);
121
+ const result = await importData({model: impexTestModel.name}, {file: blobToFile(blob, "test.json")}, mockUser);
118
122
 
119
123
  // Vérifications du résultat de l'opération
120
124
  expect(result.success).toBe(true);
121
- expect(result.jobId).not.toBeNull();
125
+ expect(result.job.jobId).not.toBeNull();
122
126
 
123
- await sleep(2000);
127
+ await sleep(8000)
124
128
 
125
129
  // Vérification directe en base de données
126
130
  const importedDocs = await testDatasColInstance.find({
@@ -136,7 +140,7 @@ describe('Intégration des fonctions d\'Import/Export', () => {
136
140
  expect(docD.inStock).toBe(true); // Vérification de la valeur par défaut
137
141
  expect(docE.price).toBe(2.00);
138
142
 
139
- }, 5000);
143
+ }, 20000);
140
144
 
141
145
  it('devrait importer des données depuis une chaîne CSV et convertir les types', async () => {
142
146
  const csvStringToImport = `name,sku,price,inStock\nProduit F,SKU-F,3.55,true\nProduit G,SKU-G,4.99,false`;
@@ -148,14 +152,13 @@ describe('Intégration des fonctions d\'Import/Export', () => {
148
152
  blob.originalFilename = 'test.csv';
149
153
 
150
154
  // Exécution de la fonction d'import
151
- const result = await importData({model:impexTestModel.name}, {file: blobToFile(blob,"test.csv")}, mockUser);
155
+ const result = await importData({model:impexTestModel.name}, {file: blobToFile(blob, "test.csv")}, mockUser);
152
156
 
153
- console.log(result)
154
157
  // Vérifications du résultat
155
158
  expect(result.success).toBe(true);
159
+ expect(result.job.jobId).not.toBeNull();
156
160
 
157
- await sleep(2000);
158
-
161
+ await sleep(8000);
159
162
  // Vérification en base de données
160
163
  const importedDocs = await testDatasColInstance.find({
161
164
  _model: impexTestModel.name,
@@ -185,16 +188,17 @@ Valide K,SKU-A,40,true`;
185
188
  blob.path = 'test.csv';
186
189
  blob.originalFilename = 'test.csv';
187
190
 
188
- const result = await importData(impexTestModel.name, {file: blobToFile(blob,"test.csv")}, 'csv', mockUser);
191
+ const result = await importData({ model: impexTestModel.name }, {file: blobToFile(blob,"test.csv")}, mockUser);
189
192
 
190
- console.log(result);
191
- // Vérifications du résultat
192
- expect(result.success).toBe(true); // L'opération globale a des erreurs
193
- expect(result.job.status).toBe('failed'); // L'opération globale a des erreurs
193
+ // L'initiation du job doit réussir
194
+ expect(result.success).toBe(true);
195
+ expect(result.job.jobId).not.toBeNull();
196
+
197
+ await sleep(8000);
194
198
 
195
199
  // Vérifier que seule les données valides sont en BDD
196
- const count = await testDatasColInstance.countDocuments({ _model: impexTestModel.name });
197
- expect(count).toBe(3);
198
- });
200
+ const count = await testDatasColInstance.countDocuments({ _model: impexTestModel.name, sku: 'SKU-H' });
201
+ expect(count).toBe(1); // Seule la ligne valide 'SKU-H' doit être insérée.
202
+ }, 20000);
199
203
  });
200
204
  });
@@ -5,30 +5,31 @@ import { Config } from '../src/config.js';
5
5
 
6
6
  import {
7
7
  modelsCollection as getAppModelsCollection,
8
- datasCollection // Accès direct pour vérifications
8
+ datasCollection, getCollection // Accès direct pour vérifications
9
9
  } from 'data-primals-engine/modules/mongodb';
10
10
  import {generateUniqueName, getUniquePort, initEngine} from "../src/setenv.js";
11
11
  import {editModel} from "../src/modules/data.js";
12
- import {getCollectionForUser} from "../src/modules/mongodb.js";
12
+ import {getCollectionForUser, getUserCollectionName} from "../src/modules/mongodb.js";
13
13
 
14
14
  let testModelsColInstance;
15
- let testDatasColInstance;
16
-
17
15
  let testModelId;
18
-
16
+ let lastUser;
19
17
  // Cette fonction va remplacer la logique de votre beforeEach pour la création de contexte
20
18
  async function setupTestContext() {
21
19
 
22
20
  const currentTestModelName = generateUniqueName('relatedModel');
23
21
  const currentRelatedModelName = generateUniqueName('comprehensiveModel');
24
22
 
23
+
25
24
  // Créer un utilisateur unique pour ce test
26
25
  const currentTestUser = {
27
- username: generateUniqueName('testuserDataIntegration'),
28
- userPlan: 'free',
26
+ username: generateUniqueName('testuserModelIntegration'),
27
+ userPlan: 'premium',
29
28
  email: generateUniqueName('test') + '@example.com'
30
29
  };
31
30
 
31
+ testModelsColInstance = getCollection("models");
32
+ const testDatasColInstance = await getCollectionForUser(currentTestUser);
32
33
 
33
34
  const relatedModelDefinition = {
34
35
  name: currentRelatedModelName,
@@ -105,43 +106,42 @@ async function setupTestContext() {
105
106
  await testDatasColInstance.deleteMany({ _user: currentTestUser.username });
106
107
  await testDatasColInstance.deleteMany({ _model: { $in: [comprehensiveTestModelDefinition.name, 'renamedTestModel'] } });
107
108
  // Retourner toutes les variables nécessaires pour un test
109
+
108
110
  return {
109
111
  currentTestUser,
112
+ coll:testDatasColInstance,
110
113
  comprehensiveTestModelDefinition,
111
114
  relatedModelDefinition
112
115
  };
113
116
  }
114
117
 
118
+
115
119
  describe('CRUD on model definitions and integrity tests', () => {
116
120
 
117
121
  beforeAll(async () =>{
118
122
  Config.Set("modules", ["mongodb", "data", "file", "bucket", "workflow","user", "assistant"]);
119
123
  await initEngine();
120
-
121
- // Initialize collection instances after the engine is ready
122
- testModelsColInstance = getAppModelsCollection;
123
- testDatasColInstance = datasCollection;
124
124
  })
125
+
125
126
  describe('editModel unit tests', () => {
126
127
 
127
- it('should create and drop index when field.index is toggled (premium user)', async () => {
128
+ it.skip('should create and drop index when field.index is toggled (premium user)', async () => {
128
129
  // --- SETUP ---
129
- const { currentTestUser, comprehensiveTestModelDefinition } = await setupTestContext();
130
- const dataCollection = await getCollectionForUser(currentTestUser);
130
+ const { coll, currentTestUser, comprehensiveTestModelDefinition } = await setupTestContext();
131
131
  const fieldToIndex = 'stringUnique'; // Utiliser un champ qui existe vraiment dans le modèle
132
132
 
133
133
  // --- FIX: Ensure the collection exists before any operation ---
134
134
  // By inserting and deleting a dummy document, we force MongoDB to create the
135
135
  // collection and its default indexes. This prevents the "ns does not exist"
136
136
  // error in asynchronous listeners (like workflow triggers).
137
- const dummyDoc = await dataCollection.insertOne({ _model: 'dummy', _user: currentTestUser.username });
138
- await dataCollection.deleteOne({ _id: dummyDoc.insertedId });
137
+ const dummyDoc = await coll.insertOne({ _model: 'dummy', _user: currentTestUser.username });
138
+ await coll.deleteOne({ _id: dummyDoc.insertedId });
139
139
 
140
140
 
141
141
  // --- VERIFICATION INITIALE ---
142
142
  // S'assurer qu'aucun index n'existe au départ.
143
143
  // Cet appel ne plantera plus car la collection est maintenant créée.
144
- const initialIndexes = await dataCollection.indexes();
144
+ const initialIndexes = await coll.indexes();
145
145
  expect(initialIndexes.some(i => i.key[fieldToIndex] === 1)).toBe(false);
146
146
 
147
147
  // --- ACTION 1 : AJOUTER UN INDEX ---
@@ -155,7 +155,7 @@ describe('CRUD on model definitions and integrity tests', () => {
155
155
 
156
156
  // --- VERIFICATION 1 ---
157
157
  // Maintenant, la collection et l'index doivent exister.
158
- const indexesAfterCreation = await dataCollection.indexes();
158
+ const indexesAfterCreation = await coll.indexes();
159
159
  const newIndex = indexesAfterCreation.find(i => i.key[fieldToIndex] === 1);
160
160
 
161
161
  expect(newIndex).toBeDefined();
@@ -175,8 +175,9 @@ describe('CRUD on model definitions and integrity tests', () => {
175
175
  await editModel(currentTestUser, testModelId, modelWithoutIndex);
176
176
 
177
177
  // --- VERIFICATION 2 ---
178
- const indexesAfterDeletion = await dataCollection.indexes();
178
+ const indexesAfterDeletion = await coll.indexes();
179
179
  expect(indexesAfterDeletion.some(i => i.key[fieldToIndex] === 1)).toBe(false);
180
+
180
181
  }, 20000);
181
182
 
182
183
  it('should not save extra, non-defined fields in the model definition', async () => {
package/test/user.test.js CHANGED
@@ -17,7 +17,7 @@ async function setupTestContext() {
17
17
 
18
18
 
19
19
  // Créer un utilisateur unique pour ce test
20
- const username = generateUniqueName('testuserDataIntegration');
20
+ const username = generateUniqueName('testuserUserIntegration');
21
21
  currentTestUser = {
22
22
  username,
23
23
  userPlan: 'free',
@@ -58,6 +58,8 @@ async function setupTestContext() {
58
58
  ]);
59
59
  testUser = {...currentTestUser, _id: users.insertedIds[0].toString(), roles: [roleEditor.toString()] };
60
60
  adminUser = {...currentTestUser, _id: users.insertedIds[1].toString(), roles: [roleEditor.toString()] };
61
+
62
+ return testDatasColInstance;
61
63
  };
62
64
  let engine;
63
65
  describe('User Permission Logic', () => {
@@ -72,26 +74,24 @@ describe('User Permission Logic', () => {
72
74
  // --- Tests pour la fonction principale de calcul ---
73
75
  describe('getUserActivePermissions()', () => {
74
76
 
75
-
76
- beforeEach(async () =>{
77
- await setupTestContext();
78
- })
79
77
  it('should return base permissions from the user\'s role', async () => {
78
+ const coll = await setupTestContext();
80
79
  const permissions = await getUserActivePermissions(testUser);
81
80
  expect(permissions).to.be.an.instanceOf(Set);
82
81
  expect(permissions.size).to.equal(2);
83
82
  expect(permissions.has('post:read')).to.be.true;
84
83
  expect(permissions.has('post:write')).to.be.true;
85
84
  expect(permissions.has('post:delete')).to.be.false;
85
+ await coll.drop();
86
86
  });
87
87
 
88
88
  it('should grant a temporary permission via an exception', async () => {
89
-
89
+ const coll = await setupTestContext();
90
90
  // Ajoute une exception qui donne la permission de supprimer, expirant demain
91
91
  const futureDate = new Date();
92
92
  futureDate.setDate(futureDate.getDate() + 1);
93
93
 
94
- await testDatasColInstance.insertOne({
94
+ await coll.insertOne({
95
95
  _model: 'userPermission',
96
96
  user: testUser._id,
97
97
  permission: permDelete,
@@ -104,15 +104,18 @@ describe('User Permission Logic', () => {
104
104
  expect(permissions.has('post:delete')).to.be.true;
105
105
 
106
106
  // Nettoyage de l'exception pour ne pas affecter les autres tests
107
- await testDatasColInstance.deleteOne({ _model: 'userPermission', user: testUser._id });
107
+ await coll.deleteOne({ _model: 'userPermission', user: testUser._id });
108
+
109
+ await coll.drop();
108
110
  });
109
111
 
110
112
  it('should NOT grant an expired temporary permission', async () => {
113
+ const coll = await setupTestContext();
111
114
  // Ajoute une exception qui a expiré hier
112
115
  const pastDate = new Date();
113
116
  pastDate.setDate(pastDate.getDate() - 1);
114
117
 
115
- await testDatasColInstance.insertOne({
118
+ await coll.insertOne({
116
119
  _model: 'userPermission',
117
120
  user: testUser._id,
118
121
  permission: permDelete,
@@ -124,15 +127,17 @@ describe('User Permission Logic', () => {
124
127
  expect(permissions.size).to.equal(2); // Revient la normale
125
128
  expect(permissions.has('post:delete')).to.be.false;
126
129
 
127
- await testDatasColInstance.deleteOne({ _model: 'userPermission', user: testUser._id });
130
+ await coll.deleteOne({ _model: 'userPermission', user: testUser._id });
131
+ await coll.drop();
128
132
  });
129
133
 
130
134
  it('should revoke a base permission via an exception', async () => {
135
+ const coll = await setupTestContext();
131
136
  // L'utilisateur est "Editor", mais on lui retire le droit d'écriture temporairement
132
137
  const futureDate = new Date();
133
138
  futureDate.setDate(futureDate.getDate() + 1);
134
139
 
135
- await testDatasColInstance.insertOne({
140
+ await coll.insertOne({
136
141
  _model: 'userPermission',
137
142
  user: testUser._id,
138
143
  permission: permWrite,
@@ -145,15 +150,17 @@ describe('User Permission Logic', () => {
145
150
  expect(permissions.has('post:read')).to.be.true;
146
151
  expect(permissions.has('post:write')).to.be.false; // La permission a été retirée
147
152
 
148
- await testDatasColInstance.deleteOne({ _model: 'userPermission', user: testUser._id });
153
+ await coll.deleteOne({ _model: 'userPermission', user: testUser._id });
154
+ await coll.drop();
149
155
  });
150
156
 
151
157
  it('should restore a revoked permission if the revocation has expired', async () => {
158
+ const coll = await setupTestContext();
152
159
  // La révocation a expiré, l'utilisateur devrait retrouver son droit d'écriture
153
160
  const pastDate = new Date();
154
161
  pastDate.setDate(pastDate.getDate() - 1);
155
162
 
156
- await testDatasColInstance.insertOne({
163
+ await coll.insertOne({
157
164
  _model: 'userPermission',
158
165
  user: testUser._id,
159
166
  permission: permWrite,
@@ -165,39 +172,39 @@ describe('User Permission Logic', () => {
165
172
  expect(permissions.size).to.equal(2);
166
173
  expect(permissions.has('post:write')).to.be.true; // La permission est de retour
167
174
 
168
- await testDatasColInstance.deleteOne({ _model: 'userPermission', user: testUser._id });
175
+ await coll.deleteOne({ _model: 'userPermission', user: testUser._id });
176
+ await coll.drop();
169
177
  });
170
178
  });
171
179
 
172
180
  // --- Tests pour la fonction publique `hasPermission` ---
173
181
  describe('hasPermission()', () => {
174
- beforeEach(async () => {
175
- await setupTestContext();
176
- });
177
182
  it('should return true for a permission the user has', async () => {
178
-
179
-
180
- console.log(await testDatasColInstance.find({ _model: 'permission' }).toArray());
181
- console.log(await testDatasColInstance.find({ _model: 'role' }).toArray());
182
- console.log(await testDatasColInstance.find({ _model: 'user' }).toArray());
183
- console.log(await testDatasColInstance.find({ _model: 'userPermission' }).toArray());
183
+ const coll = await setupTestContext();
184
184
  const result = await hasPermission('post:read', testUser);
185
185
  expect(result).to.be.true;
186
+ await coll.drop();
186
187
  });
187
188
 
188
189
  it('should return false for a permission the user does not have', async () => {
190
+ const coll = await setupTestContext();
189
191
  const result = await hasPermission('user:manage', testUser);
190
192
  expect(result).to.be.false;
193
+ await coll.drop();
191
194
  });
192
195
 
193
196
  it('should return true if user has at least one of the required permissions', async () => {
197
+ const coll = await setupTestContext();
194
198
  const result = await hasPermission(['user:manage', 'post:write'], testUser);
195
199
  expect(result).to.be.true;
200
+ await coll.drop();
196
201
  });
197
202
 
198
203
  it('should return false if user has none of the required permissions', async () => {
204
+ const coll = await setupTestContext();
199
205
  const result = await hasPermission(['user:manage', 'post:delete'], testUser);
200
206
  expect(result).to.be.false;
207
+ await coll.drop();
201
208
  });
202
209
  });
203
210
  });
@@ -0,0 +1,51 @@
1
+ import {expect, describe, it, beforeEach, afterEach, beforeAll, afterAll, vi, vitest} from 'vitest';
2
+ import ivm from "isolated-vm";
3
+ import {sleep} from "data-primals-engine/core";
4
+
5
+ vi.stubEnv('ENCRYPTION_KEY', '12345678901234567890123456789012');
6
+
7
+ async function executeSafeJavascript() {
8
+ const isolate = new ivm.Isolate()
9
+
10
+ async function myAsyncFunction(str) {
11
+ await sleep(1000);
12
+ console.log("hello"+str)
13
+ }
14
+
15
+ const context = await isolate.createContext();
16
+ const jail = context.global;
17
+
18
+ await jail.set('myAsync', new ivm.Reference(myAsyncFunction));
19
+
20
+ const fn = await context.eval(`
21
+ const normalizeArgs = args => args.map(arg => {
22
+ if (typeof arg === 'object' && arg !== null) {
23
+ return JSON.stringify(arg); // Convert objects to strings
24
+ }
25
+ return arg;
26
+ });
27
+ const t = (...args) => {
28
+ myAsync.applySyncPromise(null, normalizeArgs(args));
29
+ }
30
+ (async function untrusted() {
31
+ let str = await t("ok", {"ok":true});
32
+ return str;
33
+ })
34
+ `, { reference: true })
35
+ const value = await fn.apply(undefined, [], { result: { promise: true } })
36
+ }
37
+
38
+
39
+ beforeAll(async () => {
40
+ });
41
+ describe('VM system ingration', () => {
42
+
43
+ it('should successfully add a file with local storage', async () => {
44
+ console.log(await executeSafeJavascript({
45
+ script: 'const t = await addSync();'
46
+ }, {}, { username:'test'}));
47
+
48
+
49
+ expect(true).toBe(true);
50
+ });
51
+ });
@@ -7,6 +7,7 @@ import { modelsCollection as getAppModelsCollection, getCollectionForUser } from
7
7
  import * as workflowModule from 'data-primals-engine/modules/workflow';
8
8
  import {getUniquePort, initEngine} from "../src/setenv.js";
9
9
  import process from "process";
10
+ import {getUserCollectionName} from "../src/modules/mongodb.js";
10
11
 
11
12
 
12
13
  beforeAll(async () =>{
@@ -18,7 +19,7 @@ vi.mock('data-primals-engine/modules/workflow', { spy: true })
18
19
  const mockUser = {
19
20
  username: 'testuserWorkflow',
20
21
  _user: 'testuserWorkflow',
21
- userPlan: 'free',
22
+ userPlan: 'premium',
22
23
  email: 'testWorkflow@example.com'
23
24
  };
24
25
 
@@ -155,6 +156,10 @@ beforeEach(async () => {
155
156
  console.log({mods})
156
157
  });
157
158
 
159
+ afterAll(async () => {
160
+ const coll = await getCollectionForUser(mockUser);
161
+ await coll.drop();
162
+ })
158
163
  describe('Intégration des Workflows - triggerWorkflows', () => {
159
164
 
160
165
  let testWorkflow;
@@ -1,5 +1,5 @@
1
1
  import { ObjectId } from 'mongodb';
2
- import { expect, describe, it, beforeEach, beforeAll, vi } from 'vitest';
2
+ import {expect, describe, it, beforeEach, beforeAll, vi, afterAll} from 'vitest';
3
3
  import { Config } from "data-primals-engine/config";
4
4
  // --- Importations des modules de l'application ---
5
5
  import { insertData, editData } from 'data-primals-engine/modules/data';
@@ -7,6 +7,7 @@ import { modelsCollection as getAppModelsCollection, getCollectionForUser, getCo
7
7
  import * as workflowModule from 'data-primals-engine/modules/workflow';
8
8
  import {initEngine} from "../src/setenv.js";
9
9
  import {maxExecutionsByStep} from "../src/constants.js";
10
+ import {getUserCollectionName} from "../src/modules/mongodb.js";
10
11
 
11
12
  vi.mock('data-primals-engine/modules/workflow', { spy: true })
12
13
 
@@ -47,6 +48,10 @@ beforeEach(async () => {
47
48
  }
48
49
  });
49
50
 
51
+ afterAll(async () => {
52
+ const coll = await getCollectionForUser(mockUser);
53
+ await coll.drop();
54
+ })
50
55
  // ====================================================================================
51
56
  // =================== DÉBUT DES TESTS DE ROBUSTESSE ==================================
52
57
  // ====================================================================================