@nymphjs/server 1.0.0-beta.1 → 1.0.0-beta.100

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/src/index.test.ts CHANGED
@@ -1,27 +1,35 @@
1
1
  import express from 'express';
2
2
  import SQLite3Driver from '@nymphjs/driver-sqlite3';
3
3
  import { Nymph as NymphServer } from '@nymphjs/nymph';
4
- import { Nymph } from '@nymphjs/client-node';
5
- import { Entity } from '@nymphjs/client';
4
+ import { Nymph, Entity, HttpError } from '@nymphjs/client';
6
5
 
7
- import createServer from './index';
8
- import { EmployeeModel, Employee } from './testArtifacts';
6
+ import createServer from './index.js';
7
+ import {
8
+ EmployeeModel as EmployeeModelClass,
9
+ Employee as EmployeeClass,
10
+ RestrictedModel as RestrictedModelClass,
11
+ Restricted as RestrictedClass,
12
+ EmployeeData,
13
+ } from './testArtifacts.js';
9
14
 
10
15
  const sqliteConfig = {
11
16
  filename: ':memory:',
12
17
  };
13
18
 
14
19
  const nymphServer = new NymphServer({}, new SQLite3Driver(sqliteConfig));
15
- nymphServer.addEntityClass(EmployeeModel);
20
+ const EmployeeModel = nymphServer.addEntityClass(EmployeeModelClass);
21
+ const RestrictedModel = nymphServer.addEntityClass(RestrictedModelClass);
16
22
 
17
23
  const app = express();
18
24
  app.use('/test', createServer(nymphServer));
19
25
  const server = app.listen(5080);
20
26
 
27
+ const REST_URL = 'http://localhost:5080/test/';
21
28
  const nymph = new Nymph({
22
- restUrl: 'http://localhost:5080/test/',
29
+ restUrl: REST_URL,
23
30
  });
24
- nymph.addEntityClass(Employee);
31
+ const Employee = nymph.addEntityClass(EmployeeClass);
32
+ const Restricted = nymph.addEntityClass(RestrictedClass);
25
33
 
26
34
  describe('Nymph REST Server and Client', () => {
27
35
  async function createJane() {
@@ -126,7 +134,7 @@ describe('Nymph REST Server and Client', () => {
126
134
  {
127
135
  type: '&',
128
136
  ref: ['subordinates', jane],
129
- }
137
+ },
130
138
  );
131
139
 
132
140
  expect(checkSteve?.guid).toEqual(steve.guid);
@@ -139,7 +147,7 @@ describe('Nymph REST Server and Client', () => {
139
147
  'subordinates',
140
148
  [{ class: Employee }, { type: '&', guid: jane.guid }],
141
149
  ],
142
- }
150
+ },
143
151
  );
144
152
 
145
153
  expect(checkSteveQref?.guid).toEqual(steve.guid);
@@ -153,7 +161,7 @@ describe('Nymph REST Server and Client', () => {
153
161
  expect(entity.$hasTag('test', 'test2')).toEqual(true);
154
162
  entity.$addTag('test', 'test3', 'test4', 'test5', 'test6');
155
163
  expect(entity.$hasTag('test', 'test3', 'test4', 'test5', 'test6')).toEqual(
156
- true
164
+ true,
157
165
  );
158
166
  entity.$removeTag('test2');
159
167
  expect(!entity.$hasTag('test2')).toEqual(true);
@@ -175,10 +183,10 @@ describe('Nymph REST Server and Client', () => {
175
183
  'nymph_entity_reference',
176
184
  jane.guid,
177
185
  'Employee',
178
- ]);
179
- await entity.$ready();
186
+ ]) as EmployeeClass & EmployeeData;
187
+ await entity.$wake();
180
188
 
181
- expect(jane?.name).toEqual('Jane Doe');
189
+ expect(entity?.name).toEqual('Jane Doe');
182
190
  });
183
191
 
184
192
  it('change an entity', async () => {
@@ -229,13 +237,51 @@ describe('Nymph REST Server and Client', () => {
229
237
  {
230
238
  type: '&',
231
239
  equal: ['name', 'Jane Doe'],
232
- }
240
+ },
233
241
  );
234
242
 
235
243
  expect(jane).not.toBeNull();
236
244
  expect(jane?.guid).not.toBeNull();
237
245
  });
238
246
 
247
+ it('try to get a non-existent entity', async () => {
248
+ let error = { status: 200 };
249
+ try {
250
+ await nymph.getEntity(
251
+ {
252
+ class: Employee,
253
+ },
254
+ {
255
+ type: '&',
256
+ equal: ['name', 'Non Existent'],
257
+ },
258
+ );
259
+ } catch (e: any) {
260
+ error = e;
261
+ }
262
+ expect(error.status).toEqual(404);
263
+ });
264
+
265
+ it('try to get a non-existent entity without error', async () => {
266
+ const nymph = new Nymph({
267
+ restUrl: REST_URL,
268
+ returnNullOnNotFound: true,
269
+ });
270
+ const Employee = nymph.addEntityClass(EmployeeClass);
271
+
272
+ const nonexistent = await nymph.getEntity(
273
+ {
274
+ class: Employee,
275
+ },
276
+ {
277
+ type: '&',
278
+ equal: ['name', 'Non Existent'],
279
+ },
280
+ );
281
+
282
+ expect(nonexistent).toBeNull();
283
+ });
284
+
239
285
  it('get entities', async () => {
240
286
  for (let i = 0; i < 4; i++) {
241
287
  await createJane();
@@ -249,7 +295,7 @@ describe('Nymph REST Server and Client', () => {
249
295
  {
250
296
  type: '&',
251
297
  tag: ['employee'],
252
- }
298
+ },
253
299
  );
254
300
 
255
301
  expect(entities.length).toEqual(4);
@@ -275,13 +321,13 @@ describe('Nymph REST Server and Client', () => {
275
321
 
276
322
  const resultSelectors = await nymph.getEntities(
277
323
  { class: Employee },
278
- { type: '&', equal: ['name', 'Jane Doe'] }
324
+ { type: '&', equal: ['name', 'Jane Doe'] },
279
325
  );
280
326
 
281
327
  // Testing count return with selectors...
282
328
  const resultSelectorsCount = await nymph.getEntities(
283
329
  { class: Employee, return: 'count' },
284
- { type: '&', equal: ['name', 'Jane Doe'] }
330
+ { type: '&', equal: ['name', 'Jane Doe'] },
285
331
  );
286
332
  expect(resultSelectorsCount).toBeGreaterThanOrEqual(1);
287
333
  expect(resultSelectorsCount).toEqual(resultSelectors.length);
@@ -304,7 +350,7 @@ describe('Nymph REST Server and Client', () => {
304
350
  // Testing empty count...
305
351
  const resultSelectorsEmpty = await nymph.getEntities(
306
352
  { class: Employee, return: 'count' },
307
- { type: '&', tag: 'pickle' }
353
+ { type: '&', tag: 'pickle' },
308
354
  );
309
355
  expect(resultSelectorsEmpty).toEqual(0);
310
356
  });
@@ -323,7 +369,7 @@ describe('Nymph REST Server and Client', () => {
323
369
  {
324
370
  type: '&',
325
371
  tag: 'employee',
326
- }
372
+ },
327
373
  );
328
374
 
329
375
  expect(entities.length).toEqual(4);
@@ -349,7 +395,7 @@ describe('Nymph REST Server and Client', () => {
349
395
  {
350
396
  type: '&',
351
397
  like: ['name', '%Jane%'],
352
- }
398
+ },
353
399
  );
354
400
 
355
401
  expect(entities.length).toEqual(4);
@@ -375,7 +421,7 @@ describe('Nymph REST Server and Client', () => {
375
421
  type: '|',
376
422
  like: ['name', '%Jane%'],
377
423
  },
378
- }
424
+ },
379
425
  );
380
426
 
381
427
  expect(entities.length).toEqual(4);
@@ -410,7 +456,7 @@ describe('Nymph REST Server and Client', () => {
410
456
  },
411
457
  ],
412
458
  },
413
- }
459
+ },
414
460
  );
415
461
 
416
462
  expect(entities.length).toEqual(4);
@@ -435,7 +481,7 @@ describe('Nymph REST Server and Client', () => {
435
481
  {
436
482
  type: '&',
437
483
  guid,
438
- }
484
+ },
439
485
  );
440
486
 
441
487
  expect(check.length).toEqual(0);
@@ -458,7 +504,7 @@ describe('Nymph REST Server and Client', () => {
458
504
  {
459
505
  type: '|',
460
506
  guid: guids,
461
- }
507
+ },
462
508
  );
463
509
 
464
510
  expect(check.length).toEqual(0);
@@ -475,7 +521,7 @@ describe('Nymph REST Server and Client', () => {
475
521
  error = e;
476
522
  }
477
523
  expect(error.message).toEqual(
478
- "Can't use Entity class directly from the front end."
524
+ "Can't use Entity class directly from the front end.",
479
525
  );
480
526
  });
481
527
 
@@ -490,32 +536,103 @@ describe('Nymph REST Server and Client', () => {
490
536
  });
491
537
 
492
538
  it('handle server side static error', async () => {
493
- let error = { error: { name: '' } };
539
+ let error = { status: 0, error: { name: '' } };
494
540
  try {
495
541
  await Employee.throwErrorStatic();
496
542
  } catch (e: any) {
497
543
  error = e;
498
544
  }
545
+ expect(error.status).toEqual(500);
546
+ expect(error.error.name).toEqual('BadFunctionCallError');
547
+ });
548
+
549
+ it('handle server side static iterator error', async () => {
550
+ let error: any = { status: 0, error: { name: '' } };
551
+ const data = await Employee.throwErrorStaticIterable();
552
+
553
+ let count = 0;
554
+ for await (let value of data) {
555
+ count++;
556
+ if (value instanceof Error) {
557
+ error = value;
558
+ } else {
559
+ expect(value).toEqual(count);
560
+ }
561
+ }
562
+
563
+ expect(count).toEqual(2);
564
+ expect(error.status).toEqual(500);
499
565
  expect(error.error.name).toEqual('BadFunctionCallError');
500
566
  });
501
567
 
502
568
  it('handle server side error', async () => {
503
569
  const jane = await createJane();
504
570
 
505
- let error = { error: { name: '' } };
571
+ let error = { status: 0, error: { name: '' } };
506
572
  try {
507
573
  await jane.$throwError();
508
574
  } catch (e: any) {
509
575
  error = e;
510
576
  }
577
+ expect(error.status).toEqual(500);
511
578
  expect(error.error.name).toEqual('BadFunctionCallError');
512
579
  });
513
580
 
581
+ it('handle server side HTTP error', async () => {
582
+ const jane = await createJane();
583
+
584
+ let error = { status: 0, statusText: '', message: '' };
585
+ try {
586
+ await jane.$throwHttpError();
587
+ } catch (e: any) {
588
+ error = e;
589
+ }
590
+ expect(error.status).toEqual(501);
591
+ expect(error.statusText).toEqual('Not Implemented');
592
+ expect(error.message).toEqual('A 501 HTTP error.');
593
+ });
594
+
595
+ it('handle server side custom HTTP error', async () => {
596
+ const jane = await createJane();
597
+
598
+ let error = { status: 0, statusText: '', message: '' };
599
+ try {
600
+ await jane.$throwHttpErrorWithDescription();
601
+ } catch (e: any) {
602
+ error = e;
603
+ }
604
+ expect(error.status).toEqual(512);
605
+ expect(error.statusText).toEqual('Some Error');
606
+ expect(error.message).toEqual('A 512 HTTP error.');
607
+ });
608
+
514
609
  it('call a server side static method', async () => {
515
610
  const data = await Employee.testStatic(5);
516
611
  expect(data).toEqual(10);
517
612
  });
518
613
 
614
+ it('call a server side static iterator method', async () => {
615
+ const data = await Employee.testStaticIterable(5);
616
+
617
+ let count = 0;
618
+ for await (let value of data) {
619
+ count++;
620
+ expect(value).toEqual(5 + count);
621
+ }
622
+
623
+ expect(count).toEqual(3);
624
+ });
625
+
626
+ it('aborts a server side static iterator method', async () => {
627
+ const data = await Employee.testStaticIterableAbort();
628
+ data.abortController.abort();
629
+
630
+ // Wait 1 second to ensure server receives abort signal.
631
+ await new Promise((resolve) => setTimeout(resolve, 1000));
632
+
633
+ expect(true).toBeTruthy();
634
+ });
635
+
519
636
  it('call a stateless server side method', async () => {
520
637
  const jane = await createJane();
521
638
 
@@ -544,7 +661,7 @@ describe('Nymph REST Server and Client', () => {
544
661
  {
545
662
  class: Employee,
546
663
  },
547
- jane1.guid
664
+ jane1.guid,
548
665
  );
549
666
  if (jane1 == null || jane2 == null) {
550
667
  throw new Error('Entity is null.');
@@ -570,7 +687,7 @@ describe('Nymph REST Server and Client', () => {
570
687
  {
571
688
  class: Employee,
572
689
  },
573
- first.guid
690
+ first.guid,
574
691
  );
575
692
 
576
693
  if (second == null || second.guid == null) {
@@ -602,7 +719,7 @@ describe('Nymph REST Server and Client', () => {
602
719
  {
603
720
  class: Employee,
604
721
  },
605
- first.guid
722
+ first.guid,
606
723
  );
607
724
 
608
725
  if (second == null || second.guid == null) {
@@ -625,7 +742,7 @@ describe('Nymph REST Server and Client', () => {
625
742
  {
626
743
  type: '&',
627
744
  '!guid': first.guid,
628
- }
745
+ },
629
746
  );
630
747
 
631
748
  if (third == null || third.guid == null) {
@@ -635,6 +752,66 @@ describe('Nymph REST Server and Client', () => {
635
752
  expect(first.$is(third)).toEqual(false);
636
753
  });
637
754
 
755
+ it("doesn't allow creation of a restricted entity class", async () => {
756
+ const attempt = await Restricted.factory();
757
+ attempt.name = 'Jane Doe';
758
+
759
+ let error = null;
760
+
761
+ try {
762
+ await attempt.$save();
763
+ } catch (e: any) {
764
+ error = e;
765
+ }
766
+
767
+ expect(error).toBeInstanceOf(HttpError);
768
+ expect(error.status).toEqual(403);
769
+ });
770
+
771
+ it("doesn't allow search of a restricted entity class", async () => {
772
+ let error = null;
773
+
774
+ try {
775
+ await nymph.getEntity({
776
+ class: Restricted,
777
+ });
778
+ } catch (e: any) {
779
+ error = e;
780
+ }
781
+
782
+ expect(error).toBeInstanceOf(HttpError);
783
+ expect(error.status).toEqual(403);
784
+ });
785
+
786
+ it("doesn't allow methods of a restricted entity class", async () => {
787
+ const attempt = await Restricted.factory();
788
+ attempt.name = 'Jane Doe';
789
+
790
+ let error = null;
791
+
792
+ try {
793
+ await attempt.$testMethod(1);
794
+ } catch (e: any) {
795
+ error = e;
796
+ }
797
+
798
+ expect(error).toBeInstanceOf(HttpError);
799
+ expect(error.status).toEqual(403);
800
+ });
801
+
802
+ it("doesn't allow static methods of a restricted entity class", async () => {
803
+ let error = null;
804
+
805
+ try {
806
+ await Restricted.testStatic(1);
807
+ } catch (e: any) {
808
+ error = e;
809
+ }
810
+
811
+ expect(error).toBeInstanceOf(HttpError);
812
+ expect(error.status).toEqual(403);
813
+ });
814
+
638
815
  it('get a new UID', async () => {
639
816
  const uidValue = await nymph.newUID('employee');
640
817
  expect(typeof uidValue).toEqual('number');