@nymphjs/server 1.0.0-beta.10 → 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,14 +1,16 @@
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';
6
+ import createServer from './index.js';
8
7
  import {
9
8
  EmployeeModel as EmployeeModelClass,
10
9
  Employee as EmployeeClass,
11
- } from './testArtifacts';
10
+ RestrictedModel as RestrictedModelClass,
11
+ Restricted as RestrictedClass,
12
+ EmployeeData,
13
+ } from './testArtifacts.js';
12
14
 
13
15
  const sqliteConfig = {
14
16
  filename: ':memory:',
@@ -16,15 +18,18 @@ const sqliteConfig = {
16
18
 
17
19
  const nymphServer = new NymphServer({}, new SQLite3Driver(sqliteConfig));
18
20
  const EmployeeModel = nymphServer.addEntityClass(EmployeeModelClass);
21
+ const RestrictedModel = nymphServer.addEntityClass(RestrictedModelClass);
19
22
 
20
23
  const app = express();
21
24
  app.use('/test', createServer(nymphServer));
22
25
  const server = app.listen(5080);
23
26
 
27
+ const REST_URL = 'http://localhost:5080/test/';
24
28
  const nymph = new Nymph({
25
- restUrl: 'http://localhost:5080/test/',
29
+ restUrl: REST_URL,
26
30
  });
27
31
  const Employee = nymph.addEntityClass(EmployeeClass);
32
+ const Restricted = nymph.addEntityClass(RestrictedClass);
28
33
 
29
34
  describe('Nymph REST Server and Client', () => {
30
35
  async function createJane() {
@@ -129,7 +134,7 @@ describe('Nymph REST Server and Client', () => {
129
134
  {
130
135
  type: '&',
131
136
  ref: ['subordinates', jane],
132
- }
137
+ },
133
138
  );
134
139
 
135
140
  expect(checkSteve?.guid).toEqual(steve.guid);
@@ -142,7 +147,7 @@ describe('Nymph REST Server and Client', () => {
142
147
  'subordinates',
143
148
  [{ class: Employee }, { type: '&', guid: jane.guid }],
144
149
  ],
145
- }
150
+ },
146
151
  );
147
152
 
148
153
  expect(checkSteveQref?.guid).toEqual(steve.guid);
@@ -156,7 +161,7 @@ describe('Nymph REST Server and Client', () => {
156
161
  expect(entity.$hasTag('test', 'test2')).toEqual(true);
157
162
  entity.$addTag('test', 'test3', 'test4', 'test5', 'test6');
158
163
  expect(entity.$hasTag('test', 'test3', 'test4', 'test5', 'test6')).toEqual(
159
- true
164
+ true,
160
165
  );
161
166
  entity.$removeTag('test2');
162
167
  expect(!entity.$hasTag('test2')).toEqual(true);
@@ -178,10 +183,10 @@ describe('Nymph REST Server and Client', () => {
178
183
  'nymph_entity_reference',
179
184
  jane.guid,
180
185
  'Employee',
181
- ]);
182
- await entity.$ready();
186
+ ]) as EmployeeClass & EmployeeData;
187
+ await entity.$wake();
183
188
 
184
- expect(jane?.name).toEqual('Jane Doe');
189
+ expect(entity?.name).toEqual('Jane Doe');
185
190
  });
186
191
 
187
192
  it('change an entity', async () => {
@@ -232,13 +237,51 @@ describe('Nymph REST Server and Client', () => {
232
237
  {
233
238
  type: '&',
234
239
  equal: ['name', 'Jane Doe'],
235
- }
240
+ },
236
241
  );
237
242
 
238
243
  expect(jane).not.toBeNull();
239
244
  expect(jane?.guid).not.toBeNull();
240
245
  });
241
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
+
242
285
  it('get entities', async () => {
243
286
  for (let i = 0; i < 4; i++) {
244
287
  await createJane();
@@ -252,7 +295,7 @@ describe('Nymph REST Server and Client', () => {
252
295
  {
253
296
  type: '&',
254
297
  tag: ['employee'],
255
- }
298
+ },
256
299
  );
257
300
 
258
301
  expect(entities.length).toEqual(4);
@@ -278,13 +321,13 @@ describe('Nymph REST Server and Client', () => {
278
321
 
279
322
  const resultSelectors = await nymph.getEntities(
280
323
  { class: Employee },
281
- { type: '&', equal: ['name', 'Jane Doe'] }
324
+ { type: '&', equal: ['name', 'Jane Doe'] },
282
325
  );
283
326
 
284
327
  // Testing count return with selectors...
285
328
  const resultSelectorsCount = await nymph.getEntities(
286
329
  { class: Employee, return: 'count' },
287
- { type: '&', equal: ['name', 'Jane Doe'] }
330
+ { type: '&', equal: ['name', 'Jane Doe'] },
288
331
  );
289
332
  expect(resultSelectorsCount).toBeGreaterThanOrEqual(1);
290
333
  expect(resultSelectorsCount).toEqual(resultSelectors.length);
@@ -307,7 +350,7 @@ describe('Nymph REST Server and Client', () => {
307
350
  // Testing empty count...
308
351
  const resultSelectorsEmpty = await nymph.getEntities(
309
352
  { class: Employee, return: 'count' },
310
- { type: '&', tag: 'pickle' }
353
+ { type: '&', tag: 'pickle' },
311
354
  );
312
355
  expect(resultSelectorsEmpty).toEqual(0);
313
356
  });
@@ -326,7 +369,7 @@ describe('Nymph REST Server and Client', () => {
326
369
  {
327
370
  type: '&',
328
371
  tag: 'employee',
329
- }
372
+ },
330
373
  );
331
374
 
332
375
  expect(entities.length).toEqual(4);
@@ -352,7 +395,7 @@ describe('Nymph REST Server and Client', () => {
352
395
  {
353
396
  type: '&',
354
397
  like: ['name', '%Jane%'],
355
- }
398
+ },
356
399
  );
357
400
 
358
401
  expect(entities.length).toEqual(4);
@@ -378,7 +421,7 @@ describe('Nymph REST Server and Client', () => {
378
421
  type: '|',
379
422
  like: ['name', '%Jane%'],
380
423
  },
381
- }
424
+ },
382
425
  );
383
426
 
384
427
  expect(entities.length).toEqual(4);
@@ -413,7 +456,7 @@ describe('Nymph REST Server and Client', () => {
413
456
  },
414
457
  ],
415
458
  },
416
- }
459
+ },
417
460
  );
418
461
 
419
462
  expect(entities.length).toEqual(4);
@@ -438,7 +481,7 @@ describe('Nymph REST Server and Client', () => {
438
481
  {
439
482
  type: '&',
440
483
  guid,
441
- }
484
+ },
442
485
  );
443
486
 
444
487
  expect(check.length).toEqual(0);
@@ -461,7 +504,7 @@ describe('Nymph REST Server and Client', () => {
461
504
  {
462
505
  type: '|',
463
506
  guid: guids,
464
- }
507
+ },
465
508
  );
466
509
 
467
510
  expect(check.length).toEqual(0);
@@ -478,7 +521,7 @@ describe('Nymph REST Server and Client', () => {
478
521
  error = e;
479
522
  }
480
523
  expect(error.message).toEqual(
481
- "Can't use Entity class directly from the front end."
524
+ "Can't use Entity class directly from the front end.",
482
525
  );
483
526
  });
484
527
 
@@ -493,32 +536,103 @@ describe('Nymph REST Server and Client', () => {
493
536
  });
494
537
 
495
538
  it('handle server side static error', async () => {
496
- let error = { error: { name: '' } };
539
+ let error = { status: 0, error: { name: '' } };
497
540
  try {
498
541
  await Employee.throwErrorStatic();
499
542
  } catch (e: any) {
500
543
  error = e;
501
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);
502
565
  expect(error.error.name).toEqual('BadFunctionCallError');
503
566
  });
504
567
 
505
568
  it('handle server side error', async () => {
506
569
  const jane = await createJane();
507
570
 
508
- let error = { error: { name: '' } };
571
+ let error = { status: 0, error: { name: '' } };
509
572
  try {
510
573
  await jane.$throwError();
511
574
  } catch (e: any) {
512
575
  error = e;
513
576
  }
577
+ expect(error.status).toEqual(500);
514
578
  expect(error.error.name).toEqual('BadFunctionCallError');
515
579
  });
516
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
+
517
609
  it('call a server side static method', async () => {
518
610
  const data = await Employee.testStatic(5);
519
611
  expect(data).toEqual(10);
520
612
  });
521
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
+
522
636
  it('call a stateless server side method', async () => {
523
637
  const jane = await createJane();
524
638
 
@@ -547,7 +661,7 @@ describe('Nymph REST Server and Client', () => {
547
661
  {
548
662
  class: Employee,
549
663
  },
550
- jane1.guid
664
+ jane1.guid,
551
665
  );
552
666
  if (jane1 == null || jane2 == null) {
553
667
  throw new Error('Entity is null.');
@@ -573,7 +687,7 @@ describe('Nymph REST Server and Client', () => {
573
687
  {
574
688
  class: Employee,
575
689
  },
576
- first.guid
690
+ first.guid,
577
691
  );
578
692
 
579
693
  if (second == null || second.guid == null) {
@@ -605,7 +719,7 @@ describe('Nymph REST Server and Client', () => {
605
719
  {
606
720
  class: Employee,
607
721
  },
608
- first.guid
722
+ first.guid,
609
723
  );
610
724
 
611
725
  if (second == null || second.guid == null) {
@@ -628,7 +742,7 @@ describe('Nymph REST Server and Client', () => {
628
742
  {
629
743
  type: '&',
630
744
  '!guid': first.guid,
631
- }
745
+ },
632
746
  );
633
747
 
634
748
  if (third == null || third.guid == null) {
@@ -638,6 +752,66 @@ describe('Nymph REST Server and Client', () => {
638
752
  expect(first.$is(third)).toEqual(false);
639
753
  });
640
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
+
641
815
  it('get a new UID', async () => {
642
816
  const uidValue = await nymph.newUID('employee');
643
817
  expect(typeof uidValue).toEqual('number');