/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.io/license
 */

class TestRejection {
  prop1?: string;
  prop2?: string;
}

describe('disable wrap uncaught promise rejection', () => {
  it('should notify Zone.onHandleError if promise is uncaught', (done) => {
    let promiseError: Error | null = null;
    let zone: Zone | null = null;
    let task: Task | null = null;
    let error: Error | null = null;
    Zone.current
      .fork({
        name: 'promise-error',
        onHandleError: (
          delegate: ZoneDelegate,
          current: Zone,
          target: Zone,
          error: any,
        ): boolean => {
          promiseError = error;
          delegate.handleError(target, error);
          return false;
        },
      })
      .run(() => {
        zone = Zone.current;
        task = Zone.currentTask;
        error = new Error('rejectedErrorShouldBeHandled');
        try {
          // throw so that the stack trace is captured
          throw error;
        } catch (e) {}
        Promise.reject(error);
        expect(promiseError).toBe(null);
      });
    setTimeout((): any => null);
    setTimeout(() => {
      expect(promiseError).toBe(error);
      expect((promiseError as any)['rejection']).toBe(undefined);
      expect((promiseError as any)['zone']).toBe(undefined);
      expect((promiseError as any)['task']).toBe(undefined);
      done();
    });
  });

  it('should print original information when a non-Error object is used for rejection', (done) => {
    let promiseError: Error | null = null;
    let rejectObj: TestRejection;
    Zone.current
      .fork({
        name: 'promise-error',
        onHandleError: (
          delegate: ZoneDelegate,
          current: Zone,
          target: Zone,
          error: any,
        ): boolean => {
          promiseError = error;
          delegate.handleError(target, error);
          return false;
        },
      })
      .run(() => {
        rejectObj = new TestRejection();
        rejectObj.prop1 = 'value1';
        rejectObj.prop2 = 'value2';
        (rejectObj as any).message = 'rejectMessage';
        Promise.reject(rejectObj);
        expect(promiseError).toBe(null);
      });
    setTimeout((): any => null);
    setTimeout(() => {
      expect(promiseError).toEqual(rejectObj as any);
      done();
    });
  });

  it('should print original information when a primitive value is used for rejection', (done) => {
    let promiseError: number | null = null;
    Zone.current
      .fork({
        name: 'promise-error',
        onHandleError: (
          delegate: ZoneDelegate,
          current: Zone,
          target: Zone,
          error: any,
        ): boolean => {
          promiseError = error;
          delegate.handleError(target, error);
          return false;
        },
      })
      .run(() => {
        Promise.reject(42);
        expect(promiseError).toBe(null);
      });
    setTimeout((): any => null);
    setTimeout(() => {
      expect(promiseError).toBe(42);
      done();
    });
  });
});
