tm1npm 1.5.3 → 2.0.0

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 (78) hide show
  1. package/CHANGELOG.md +89 -0
  2. package/lib/index.d.ts +1 -1
  3. package/lib/index.d.ts.map +1 -1
  4. package/lib/services/ApplicationService.d.ts +19 -3
  5. package/lib/services/ApplicationService.d.ts.map +1 -1
  6. package/lib/services/ApplicationService.js +232 -6
  7. package/lib/services/AsyncOperationService.d.ts +8 -1
  8. package/lib/services/AsyncOperationService.d.ts.map +1 -1
  9. package/lib/services/AsyncOperationService.js +69 -26
  10. package/lib/services/ElementService.d.ts +67 -1
  11. package/lib/services/ElementService.d.ts.map +1 -1
  12. package/lib/services/ElementService.js +214 -0
  13. package/lib/services/FileService.d.ts.map +1 -1
  14. package/lib/services/HierarchyService.d.ts +26 -0
  15. package/lib/services/HierarchyService.d.ts.map +1 -1
  16. package/lib/services/HierarchyService.js +306 -0
  17. package/lib/services/ProcessService.d.ts +40 -22
  18. package/lib/services/ProcessService.d.ts.map +1 -1
  19. package/lib/services/ProcessService.js +118 -111
  20. package/lib/services/RestService.d.ts +213 -25
  21. package/lib/services/RestService.d.ts.map +1 -1
  22. package/lib/services/RestService.js +841 -263
  23. package/lib/services/SubsetService.d.ts +2 -0
  24. package/lib/services/SubsetService.d.ts.map +1 -1
  25. package/lib/services/SubsetService.js +33 -0
  26. package/lib/services/TM1Service.d.ts +44 -1
  27. package/lib/services/TM1Service.d.ts.map +1 -1
  28. package/lib/services/TM1Service.js +96 -4
  29. package/lib/services/index.d.ts +1 -1
  30. package/lib/services/index.d.ts.map +1 -1
  31. package/lib/tests/100PercentParityCheck.test.js +23 -6
  32. package/lib/tests/applicationService.issue38.test.d.ts +5 -0
  33. package/lib/tests/applicationService.issue38.test.d.ts.map +1 -0
  34. package/lib/tests/applicationService.issue38.test.js +237 -0
  35. package/lib/tests/asyncOperationService.test.js +51 -45
  36. package/lib/tests/bugfix28.test.js +12 -4
  37. package/lib/tests/elementService.issue37.test.d.ts +5 -0
  38. package/lib/tests/elementService.issue37.test.d.ts.map +1 -0
  39. package/lib/tests/elementService.issue37.test.js +413 -0
  40. package/lib/tests/elementService.issue38.test.d.ts +5 -0
  41. package/lib/tests/elementService.issue38.test.d.ts.map +1 -0
  42. package/lib/tests/elementService.issue38.test.js +79 -0
  43. package/lib/tests/hierarchyService.issue38.test.d.ts +5 -0
  44. package/lib/tests/hierarchyService.issue38.test.d.ts.map +1 -0
  45. package/lib/tests/hierarchyService.issue38.test.js +460 -0
  46. package/lib/tests/processService.comprehensive.test.js +9 -9
  47. package/lib/tests/processService.test.js +234 -0
  48. package/lib/tests/restService.test.d.ts +0 -4
  49. package/lib/tests/restService.test.d.ts.map +1 -1
  50. package/lib/tests/restService.test.js +1558 -143
  51. package/lib/tests/subsetService.issue38.test.d.ts +5 -0
  52. package/lib/tests/subsetService.issue38.test.d.ts.map +1 -0
  53. package/lib/tests/subsetService.issue38.test.js +113 -0
  54. package/lib/tests/tm1Service.test.js +80 -8
  55. package/package.json +1 -1
  56. package/src/index.ts +1 -1
  57. package/src/services/ApplicationService.ts +282 -10
  58. package/src/services/AsyncOperationService.ts +76 -29
  59. package/src/services/ElementService.ts +322 -1
  60. package/src/services/FileService.ts +3 -3
  61. package/src/services/HierarchyService.ts +419 -1
  62. package/src/services/ProcessService.ts +185 -142
  63. package/src/services/RestService.ts +1021 -267
  64. package/src/services/SubsetService.ts +48 -0
  65. package/src/services/TM1Service.ts +127 -6
  66. package/src/services/index.ts +1 -1
  67. package/src/tests/100PercentParityCheck.test.ts +29 -8
  68. package/src/tests/applicationService.issue38.test.ts +293 -0
  69. package/src/tests/asyncOperationService.test.ts +52 -48
  70. package/src/tests/bugfix28.test.ts +12 -4
  71. package/src/tests/elementService.issue37.test.ts +571 -0
  72. package/src/tests/elementService.issue38.test.ts +103 -0
  73. package/src/tests/hierarchyService.issue38.test.ts +599 -0
  74. package/src/tests/processService.comprehensive.test.ts +10 -10
  75. package/src/tests/processService.test.ts +295 -3
  76. package/src/tests/restService.test.ts +1844 -139
  77. package/src/tests/subsetService.issue38.test.ts +182 -0
  78. package/src/tests/tm1Service.test.ts +95 -11
@@ -312,6 +312,240 @@ describe('ProcessService Tests', () => {
312
312
  expect(mockRestService.get).toHaveBeenCalled();
313
313
  console.log('✅ Debug operations handled for existing processes');
314
314
  });
315
+ test('debugGetBreakpoints should return ProcessDebugBreakpoint array', async () => {
316
+ mockRestService.get.mockResolvedValue(createMockResponse({
317
+ value: [
318
+ {
319
+ '@odata.type': '#ibm.tm1.api.v1.ProcessDebugContextLineBreakpoint',
320
+ ID: 1,
321
+ Enabled: true,
322
+ HitMode: 'BreakAlways',
323
+ HitCount: 0,
324
+ Expression: '',
325
+ ProcessName: 'TestProcess',
326
+ Procedure: 'Prolog',
327
+ LineNumber: 5
328
+ }
329
+ ]
330
+ }));
331
+ const result = await processService.debugGetBreakpoints('debug-123');
332
+ expect(result).toHaveLength(1);
333
+ expect(result[0].breakpointId).toBe(1);
334
+ expect(mockRestService.get).toHaveBeenCalledWith("/ProcessDebugContexts('debug-123')/Breakpoints");
335
+ });
336
+ test('debugAddBreakpoint should delegate to debugAddBreakpoints', async () => {
337
+ mockRestService.post.mockResolvedValue(createMockResponse({}));
338
+ const { ProcessDebugBreakpoint: BP, BreakPointType: BPType, HitMode: HM } = require('../objects/ProcessDebugBreakpoint');
339
+ const bp = new BP(1, BPType.PROCESS_DEBUG_CONTEXT_LINE_BREAK_POINT, true, HM.BREAK_ALWAYS);
340
+ await processService.debugAddBreakpoint('debug-456', bp);
341
+ // Should POST a JSON array (delegated to debugAddBreakpoints)
342
+ const postCall = mockRestService.post.mock.calls[0];
343
+ expect(postCall[0]).toBe("/ProcessDebugContexts('debug-456')/Breakpoints");
344
+ const postedBody = JSON.parse(postCall[1]);
345
+ expect(Array.isArray(postedBody)).toBe(true);
346
+ expect(postedBody).toHaveLength(1);
347
+ });
348
+ test('debugRemoveBreakpoint should DELETE correct URL', async () => {
349
+ mockRestService.delete.mockResolvedValue(createMockResponse({}));
350
+ await processService.debugRemoveBreakpoint('debug-789', 3);
351
+ expect(mockRestService.delete).toHaveBeenCalledWith("/ProcessDebugContexts('debug-789')/Breakpoints('3')");
352
+ });
353
+ });
354
+ describe('Process Async Polling', () => {
355
+ test('pollExecuteWithReturn should return parsed result on success', async () => {
356
+ // retrieve_async_response returns an AxiosResponse; the execute summary
357
+ // lives in .data. Tests that mocked the raw body directly did not
358
+ // reflect production shape and silently passed against the untyped
359
+ // parser signature.
360
+ mockRestService.retrieve_async_response = jest.fn().mockResolvedValue({
361
+ status: 200,
362
+ data: {
363
+ ProcessExecuteStatusCode: 'CompletedSuccessfully',
364
+ ErrorLogFile: null
365
+ }
366
+ });
367
+ const result = await processService.pollExecuteWithReturn('async-001');
368
+ expect(result).toEqual([true, 'CompletedSuccessfully', null]);
369
+ expect(mockRestService.retrieve_async_response).toHaveBeenCalledWith('async-001');
370
+ });
371
+ test('pollExecuteWithReturn should return error log file when present', async () => {
372
+ mockRestService.retrieve_async_response = jest.fn().mockResolvedValue({
373
+ status: 200,
374
+ data: {
375
+ ProcessExecuteStatusCode: 'CompletedWithMessages',
376
+ ErrorLogFile: { Filename: 'TM1ProcessError_20240101.log' }
377
+ }
378
+ });
379
+ const result = await processService.pollExecuteWithReturn('async-002');
380
+ expect(result).toEqual([false, 'CompletedWithMessages', 'TM1ProcessError_20240101.log']);
381
+ });
382
+ test('pollExecuteWithReturn should return null for 404 (not ready)', async () => {
383
+ const { TM1RestException } = require('../exceptions/TM1Exception');
384
+ mockRestService.retrieve_async_response = jest.fn().mockRejectedValue(new TM1RestException('Not found', 404));
385
+ const result = await processService.pollExecuteWithReturn('async-003');
386
+ expect(result).toBeNull();
387
+ });
388
+ test('pollExecuteWithReturn should return null for 202 (accepted/pending)', async () => {
389
+ // After the #80 refactor retrieve_async_response returns the raw AxiosResponse
390
+ // instead of throwing on 202; the pending path is now signalled by status === 202.
391
+ mockRestService.retrieve_async_response = jest.fn().mockResolvedValue({
392
+ status: 202,
393
+ data: {}
394
+ });
395
+ const result = await processService.pollExecuteWithReturn('async-004');
396
+ expect(result).toBeNull();
397
+ });
398
+ test('pollExecuteWithReturn should throw on unexpected errors', async () => {
399
+ const { TM1RestException } = require('../exceptions/TM1Exception');
400
+ const serverError = new TM1RestException('Internal Server Error', 500);
401
+ mockRestService.retrieve_async_response = jest.fn().mockRejectedValue(serverError);
402
+ await expect(processService.pollExecuteWithReturn('async-005'))
403
+ .rejects.toThrow('Internal Server Error');
404
+ });
405
+ });
406
+ describe('Process Compile (unbound)', () => {
407
+ test('compileProcess should POST Process body to /CompileProcess', async () => {
408
+ mockRestService.post.mockResolvedValue(createMockResponse({ value: [] }));
409
+ const testProcess = new Process_1.Process('TestProcess', false);
410
+ const result = await processService.compileProcess(testProcess);
411
+ expect(result).toEqual([]);
412
+ const postCall = mockRestService.post.mock.calls[0];
413
+ expect(postCall[0]).toBe('/CompileProcess');
414
+ const payload = JSON.parse(postCall[1]);
415
+ expect(payload.Process).toBeDefined();
416
+ expect(payload.Process.Name).toBe('TestProcess');
417
+ });
418
+ test('compileProcess should return syntax errors when present', async () => {
419
+ const errors = [
420
+ { LineNumber: 1, Message: 'Syntax error on line 1' }
421
+ ];
422
+ mockRestService.post.mockResolvedValue(createMockResponse({ value: errors }));
423
+ const testProcess = new Process_1.Process('BadProcess', false);
424
+ const result = await processService.compileProcess(testProcess);
425
+ expect(result).toHaveLength(1);
426
+ expect(result[0].Message).toBe('Syntax error on line 1');
427
+ });
428
+ });
429
+ describe('evaluateTiExpression', () => {
430
+ test('should evaluate a TI expression and return the result', async () => {
431
+ // Mock compileProcess (no errors)
432
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({ value: [] }));
433
+ // Mock create (process creation)
434
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({}, 201));
435
+ // Mock debugProcess
436
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({
437
+ ID: 'debug-eval-123',
438
+ CallStack: [],
439
+ Breakpoints: []
440
+ }));
441
+ // Mock debugAddBreakpoint (via debugAddBreakpoints)
442
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({}));
443
+ // Mock debugContinue (first call - run to breakpoint)
444
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({}));
445
+ mockRestService.get.mockResolvedValueOnce(createMockResponse({
446
+ CallStack: [{ Variables: [{ Name: 'sFunc', Value: '2024-01-01' }] }]
447
+ }));
448
+ // Mock debugGetVariableValues
449
+ mockRestService.get.mockResolvedValueOnce(createMockResponse({
450
+ CallStack: [{ Variables: [{ Name: 'sFunc', Value: '2024-01-01' }] }]
451
+ }));
452
+ // Mock debugContinue (second call - finish)
453
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({}));
454
+ mockRestService.get.mockResolvedValueOnce(createMockResponse({ CallStack: [] }));
455
+ // Mock delete (cleanup)
456
+ mockRestService.delete.mockResolvedValueOnce(createMockResponse({}, 204));
457
+ const result = await processService.evaluateTiExpression('NOW;');
458
+ expect(result).toBe('2024-01-01');
459
+ });
460
+ test('should strip leading "=" prefix from formula', async () => {
461
+ // Mock compileProcess
462
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({ value: [] }));
463
+ // Mock create
464
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({}, 201));
465
+ // Mock debugProcess
466
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({
467
+ ID: 'debug-eq-123',
468
+ CallStack: []
469
+ }));
470
+ // Mock debugAddBreakpoint
471
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({}));
472
+ // Mock debugContinue
473
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({}));
474
+ mockRestService.get.mockResolvedValueOnce(createMockResponse({
475
+ CallStack: [{ Variables: [{ Name: 'sFunc', Value: '42' }] }]
476
+ }));
477
+ // Mock debugGetVariableValues
478
+ mockRestService.get.mockResolvedValueOnce(createMockResponse({
479
+ CallStack: [{ Variables: [{ Name: 'sFunc', Value: '42' }] }]
480
+ }));
481
+ // Mock debugContinue
482
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({}));
483
+ mockRestService.get.mockResolvedValueOnce(createMockResponse({ CallStack: [] }));
484
+ // Mock delete
485
+ mockRestService.delete.mockResolvedValueOnce(createMockResponse({}, 204));
486
+ // Leading "=" is stripped (Excel-style formula prefix)
487
+ const result = await processService.evaluateTiExpression('= NumberToString(42);');
488
+ expect(result).toBe('42');
489
+ // Verify the formula was stripped correctly
490
+ const compileCall = mockRestService.post.mock.calls[0];
491
+ const compilePayload = JSON.parse(compileCall[1]);
492
+ expect(compilePayload.Process.PrologProcedure).toContain('sFunc = NumberToString(42);');
493
+ });
494
+ test('should not mangle formulas with embedded "=" characters', async () => {
495
+ // Mock compileProcess
496
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({ value: [] }));
497
+ // Mock create
498
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({}, 201));
499
+ // Mock debugProcess
500
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({
501
+ ID: 'debug-embed-123',
502
+ CallStack: []
503
+ }));
504
+ // Mock debugAddBreakpoint
505
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({}));
506
+ // Mock debugContinue
507
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({}));
508
+ mockRestService.get.mockResolvedValueOnce(createMockResponse({
509
+ CallStack: [{ Variables: [{ Name: 'sFunc', Value: '1' }] }]
510
+ }));
511
+ // Mock debugGetVariableValues
512
+ mockRestService.get.mockResolvedValueOnce(createMockResponse({
513
+ CallStack: [{ Variables: [{ Name: 'sFunc', Value: '1' }] }]
514
+ }));
515
+ // Mock debugContinue
516
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({}));
517
+ mockRestService.get.mockResolvedValueOnce(createMockResponse({ CallStack: [] }));
518
+ // Mock delete
519
+ mockRestService.delete.mockResolvedValueOnce(createMockResponse({}, 204));
520
+ // Formula with embedded "=" should NOT be mangled
521
+ const result = await processService.evaluateTiExpression('IF(1=1, "yes", "no");');
522
+ expect(result).toBe('1');
523
+ // Verify the full formula is preserved
524
+ const compileCall = mockRestService.post.mock.calls[0];
525
+ const compilePayload = JSON.parse(compileCall[1]);
526
+ expect(compilePayload.Process.PrologProcedure).toContain('sFunc = IF(1=1, "yes", "no");');
527
+ });
528
+ test('should throw readable error on syntax errors from compileProcess', async () => {
529
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({
530
+ value: [{ LineNumber: 1, Message: 'Unexpected token' }]
531
+ }));
532
+ await expect(processService.evaluateTiExpression('INVALID_FUNC();'))
533
+ .rejects.toThrow('Line 1: Unexpected token');
534
+ });
535
+ test('should clean up temp process even on debug failure', async () => {
536
+ // Mock compileProcess (no errors)
537
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({ value: [] }));
538
+ // Mock create
539
+ mockRestService.post.mockResolvedValueOnce(createMockResponse({}, 201));
540
+ // Mock debugProcess - fails
541
+ mockRestService.post.mockRejectedValueOnce(new Error('Debug session failed'));
542
+ // Mock delete (cleanup should still happen)
543
+ mockRestService.delete.mockResolvedValueOnce(createMockResponse({}, 204));
544
+ await expect(processService.evaluateTiExpression('NOW;'))
545
+ .rejects.toThrow('Debug session failed');
546
+ // Verify delete was called for cleanup
547
+ expect(mockRestService.delete).toHaveBeenCalled();
548
+ });
315
549
  });
316
550
  });
317
551
  //# sourceMappingURL=processService.test.js.map
@@ -1,6 +1,2 @@
1
- /**
2
- * RestService Tests for tm1npm
3
- * Comprehensive tests for TM1 REST API operations with proper mocking
4
- */
5
1
  export {};
6
2
  //# sourceMappingURL=restService.test.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"restService.test.d.ts","sourceRoot":"","sources":["../../src/tests/restService.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
1
+ {"version":3,"file":"restService.test.d.ts","sourceRoot":"","sources":["../../src/tests/restService.test.ts"],"names":[],"mappings":""}