7

I have a little function in Angular 7 that I am testing with Jest. The function looks like this:

private checkFreeProduct(allowance: SubscriberConnectivityAllowanceInterface): Observable<SubscriberConnectivityAllowanceInterface> {

    // TODO: This is currently just a temp function to be extended when required
    return of(allowance);

}

As you can see, for the moment all it is doing is creating an observable from its input, but it is under development and will be extended.

I am testing it with Jest like this:

it('should return an observable of the allowance', () => {

    const allowance: SubscriberConnectivityAllowanceInterface = {
        hotspotAuthenticated: HotspotAuthenticationEnum.TRUE,
        remainingOctets: 100,
        remainingSeconds: 200,
        activeProductCost: ConnectivityProductCostEnum.PAID,
        activeProductDuration: ConnectivityProductDurationEnum.FLIGHT,
        activeProductType: ConnectivityProductTypeEnum.PREMIUM,
        connectivityProducts: []
    };

    const expected = hot('a|', {
        a: allowance
    });

    expect(hotspotService['checkFreeProduct'](allowance)).toBeObservable(expected);

});

However, the test is failing because of some timing issue. The expected observable result looks like this:

[
  {
    "frame": 0,
    "notification": {
      "error": undefined,
      "hasValue": true,
      "kind": "N",
      "value": {
        "activeProductCost": "paid",
        "activeProductDuration": "flight",
        "activeProductType": "premium",
        "connectivityProducts": [],
        "hotspotAuthenticated": 1,
        "remainingOctets": 100,
        "remainingSeconds": 200
      }
    }
  },
  {
    "frame": 10,
    "notification": {
      "error": undefined,
      "hasValue": false,
      "kind": "C",
      "value": undefined
    }
  }
]

and the observable created from the function call hotspotService['checkFreeProduct'](allowance) looks like this:

[
  {
    "frame": 0,
    "notification": {
      "error": undefined,
      "hasValue": true,
      "kind": "N",
      "value": {
        "activeProductCost": "paid",
        "activeProductDuration": "flight",
        "activeProductType": "premium",
        "connectivityProducts": [],
        "hotspotAuthenticated": 1,
        "remainingOctets": 100,
        "remainingSeconds": 200
      }
    }
  },
  {
    "frame": 0, // <------- this is the only difference
    "notification": {
      "error": undefined,
      "hasValue": false,
      "kind": "C",
      "value": undefined
    }
  }
]

Now I'm not exactly sure why there are two emissions from these observables, but I'll go with it. What I don't understand is why the observable from the function call emits two events, both on frame 0. I have tried both hot() and cold(), and have experimented with various marbles in these calls but no joy. Can someone please explain?

Liam
  • 27,717
  • 28
  • 128
  • 190
serlingpa
  • 12,024
  • 24
  • 80
  • 130
  • Its almost 2 yrs on this post, but still can you accept my response as the answer if it helped you so that someone who comes to this post knows there is a solution for this question . Thanks. – GokuSS3 Dec 16 '22 at 10:21

1 Answers1

8

The question you asked about two events emitted is because of the marble hot('a|') - 1st one is emitting the value that you wish to assert 'a' and second is emitted to indicate the completion of the hot observable '|'. This can be inferred from the Notification -> Kind property in those events that you have added in your question. Ex: "kind": "N" -> Value emitted. kind": "C" -> completion of observable.

Answer: To fix your unit test, just change the marble to '(a|)', so that both of them are emitted in the same time frame. I have tested this and it works.

Reason for different time frames: The hot and cold create observable streams that emit values on specific time intervals. Marbles denote actions that happen over time on observables.

  • - - denotes a unit of time frame.
  • [a-z0-9] - denotes values emitted from stream.
  • | - denotes completion of observable stream.
  • # - denotes error in observable stream.
  • () - denotes grouping of values emitted on the same time frame.

For your solution, hot('(a|')) - means emit both the value a and complete the observable stream within the same time frame.

References: https://github.com/jisaacks/RxJS/blob/master/doc/writing-marble-tests.md https://medium.com/@bencabanes/marble-testing-observable-introduction-1f5ad39231c

Liam
  • 27,717
  • 28
  • 128
  • 190
GokuSS3
  • 123
  • 1
  • 11
  • *As you can see, for the moment all it is doing is creating an observable from its input, but it is under development and will be extended* – Liam Mar 12 '20 at 08:24
  • ok. I just wanted to give an alternate way to test the service. I have updated my answer – GokuSS3 Mar 12 '20 at 10:36
  • This is getting there but needs to be better explained. For a start, I'd move your Answer to the top and work from that, not as a footnote – Liam Mar 12 '20 at 11:23
  • Added some explanation and links. – GokuSS3 Mar 12 '20 at 12:38
  • I've edited your answer to show what I mean, feel free to undo but that's what I'd do, the first bit is irrelevant to the actual question getting asked – Liam Mar 12 '20 at 12:43
  • Got it. The 1st bit was something that was to be removed but i didnt. But the marbles should have helped you to move ahead with your unit test. – GokuSS3 Mar 16 '20 at 05:12
  • @Liam: Its almost 2 yrs on this post, but still can you accept my response as the answer if it helped you so that someone who comes to this post knows there is a solution for this question . Thanks. – GokuSS3 Dec 16 '22 at 07:38
  • this isn't my question – Liam Dec 16 '22 at 08:56