@angular/core/testing#flush TypeScript Examples

The following examples show how to use @angular/core/testing#flush. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: block-card.component.spec.ts    From slate-angular with MIT License 6 votes vote down vote up
describe('Block Card Component', () => {
    let component: ImageEditableComponent;
    let fixture: ComponentFixture<ImageEditableComponent>;

    beforeEach(fakeAsync(() => {
        configureBasicEditableTestingModule([ImageEditableComponent]);
        fixture = TestBed.createComponent(ImageEditableComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
        flush();
        fixture.detectChanges();
    }));    

    it('The block-card component should be created', fakeAsync(() => {
        let blockCardElement: HTMLElement;
        blockCardElement = fixture.debugElement.query(By.css('.slate-block-card')).nativeElement;
        expect(blockCardElement).toBeTruthy();
    }));
});
Example #2
Source File: angular-context.ts    From s-libs with MIT License 5 votes vote down vote up
/**
   * Performs any cleanup needed at the end of each test. This base implementation calls {@linkcode https://angular.io/api/core/testing/discardPeriodicTasks|discardPeriodicTasks} and [flush]{https://angular.io/api/core/testing/flush|flush} to avoid an error from the `fakeAsync` zone.
   */
  protected cleanUp(): void {
    discardPeriodicTasks();
    flush();
    AngularContext.#current = undefined;
  }
Example #3
Source File: fake-async-harness-environment.ts    From s-libs with MIT License 5 votes vote down vote up
async waitForTasksOutsideAngular(): Promise<void> {
    flush();
  }
Example #4
Source File: angular-editor.spec.ts    From slate-angular with MIT License 5 votes vote down vote up
describe('AngularEditor', () => {
    let component: BasicEditableComponent;
    let fixture: ComponentFixture<BasicEditableComponent>;

    beforeEach(fakeAsync(() => {
        configureBasicEditableTestingModule([BasicEditableComponent]);
        fixture = TestBed.createComponent(BasicEditableComponent);
        component = fixture.componentInstance;
        component.value = createEmptyDocument() as Element[];
        fixture.detectChanges();
        flush();
        fixture.detectChanges();
    }));

    afterEach(() => {
        fixture.destroy();
    });

    it('should fixed cursor after zero width char when text node is empty', () => {
        Transforms.select(component.editor, {
            anchor: {
                path: [0, 0],
                offset: 0
            },
            focus: {
                path: [0, 0],
                offset: 0
            }
        });
        const nativeRange = AngularEditor.toDOMRange(component.editor, component.editor.selection);
        expect(nativeRange.startOffset).toEqual(1);
        expect(nativeRange.endOffset).toEqual(1);
    });

    it('should fixed cursor to location after inserted text when insertText', fakeAsync(() => {
        const insertText = 'test';
        Transforms.select(component.editor, {
            anchor: {
                path: [0, 0],
                offset: 0
            },
            focus: {
                path: [0, 0],
                offset: 0
            }
        });
        tick(100);
        Transforms.insertText(component.editor, insertText);
        tick(100);
        const nativeRange = AngularEditor.toDOMRange(component.editor, component.editor.selection);
        expect(nativeRange.startOffset).toEqual(insertText.length);
        expect(nativeRange.endOffset).toEqual(insertText.length);
    }));
});
Example #5
Source File: container.spec.ts    From slate-angular with MIT License 5 votes vote down vote up
describe('ViewContainer Class', () => {
    let component: AdvancedEditableComponent;
    let fixture: ComponentFixture<AdvancedEditableComponent>;
    let editor: Editor;

    beforeEach(fakeAsync(() => {
        configureBasicEditableTestingModule([AdvancedEditableComponent, TestingLeafComponent], [TestingLeafComponent]);
        fixture = TestBed.createComponent(AdvancedEditableComponent);
        component = fixture.componentInstance;
        component.value = createMutipleParagraph();
        editor = component.editor;
    }));
    
    describe('move nodes', () => {
        it('move node from [0] to [1]', fakeAsync(() => {
            fixture.detectChanges();
            flush();
            fixture.detectChanges();
            const parent = AngularEditor.toDOMNode(editor, editor);
            Transforms.moveNodes(editor, { at: [0], to: [1] });
            fixture.detectChanges();
            flush();
            fixture.detectChanges();
            expect(Node.string(editor.children[0])).toEqual('1');
            const newP0 = parent.children.item(0) as HTMLElement;
            const newP1 = parent.children.item(1) as HTMLElement;
            expect(newP0.textContent).toEqual('1');
            expect(newP1.textContent).toEqual('0');
        }));
        it('move node from [2] to [5]', fakeAsync(() => {
            fixture.detectChanges();
            flush();
            fixture.detectChanges();
            const parent = AngularEditor.toDOMNode(editor, editor);
            Transforms.moveNodes(editor, { at: [2], to: [5] });
            fixture.detectChanges();
            flush();
            fixture.detectChanges();
            const newP5 = parent.children.item(5) as HTMLElement;
            const newP3 = parent.children.item(3) as HTMLElement;
            expect(newP5.textContent).toEqual('2');
            expect(newP3.textContent).toEqual('4');
        }));
        it('move node from [5] to [2]', fakeAsync(() => {
            fixture.detectChanges();
            flush();
            fixture.detectChanges();
            const parent = AngularEditor.toDOMNode(editor, editor);
            Transforms.moveNodes(editor, { at: [5], to: [2] });
            fixture.detectChanges();
            flush();
            fixture.detectChanges();
            const newP2 = parent.children.item(2) as HTMLElement;
            const newP5 = parent.children.item(5) as HTMLElement;
            expect(newP2.textContent).toEqual('5');
            expect(newP5.textContent).toEqual('4');
        }));
    });
});
Example #6
Source File: auth.interceptor.spec.ts    From auth0-angular with MIT License 4 votes vote down vote up
// NOTE: Read Async testing: https://github.com/angular/angular/issues/25733#issuecomment-636154553

describe('The Auth HTTP Interceptor', () => {
  let httpClient: HttpClient;
  let httpTestingController: HttpTestingController;
  let auth0Client: Auth0Client;
  let req: TestRequest;
  let authState: AuthState;
  const testData: Data = { message: 'Hello, world' };

  const assertAuthorizedApiCallTo = (
    url: string,
    done: () => void,
    method = 'get'
  ) => {
    httpClient.request(method, url).subscribe(done);
    flush();
    req = httpTestingController.expectOne(url);

    expect(req.request.headers.get('Authorization')).toBe(
      'Bearer access-token'
    );
  };

  const assertPassThruApiCallTo = (url: string, done: () => void) => {
    httpClient.get<Data>(url).subscribe(done);
    flush();
    req = httpTestingController.expectOne(url);
    expect(req.request.headers.get('Authorization')).toBeFalsy();
  };

  let config: Partial<AuthConfig>;

  beforeEach(() => {
    req = undefined as any;

    auth0Client = new Auth0Client({
      domain: '',
      client_id: '',
    });

    spyOn(auth0Client, 'getTokenSilently').and.resolveTo('access-token');

    config = {
      httpInterceptor: {
        allowedList: [
          '',
          'https://my-api.com/api/photos',
          'https://my-api.com/api/people*',
          'https://my-api.com/orders',
          {
            uri: 'https://my-api.com/api/orders',
            allowAnonymous: true,
          },
          {
            uri: 'https://my-api.com/api/addresses',
            tokenOptions: {
              audience: 'audience',
              scope: 'scope',
            },
          },
          {
            uri: 'https://my-api.com/api/calendar*',
          },
          {
            uri: 'https://my-api.com/api/register',
            httpMethod: HttpMethod.Post,
          },
          {
            uriMatcher: (uri) => uri.indexOf('/api/contact') !== -1,
            httpMethod: HttpMethod.Post,
            tokenOptions: {
              audience: 'audience',
              scope: 'scope',
            },
          },
        ],
      },
    };

    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [
        {
          provide: HTTP_INTERCEPTORS,
          useClass: AuthHttpInterceptor,
          multi: true,
        },
        {
          provide: Auth0ClientService,
          useValue: auth0Client,
        },
        {
          provide: AuthClientConfig,
          useValue: { get: () => config },
        },
      ],
    });

    httpClient = TestBed.inject(HttpClient);
    httpTestingController = TestBed.inject(HttpTestingController);
    authState = TestBed.inject(AuthState);

    spyOn(authState, 'setError').and.callThrough();
  });

  afterEach(() => {
    httpTestingController.verify();
    if (req) {
      req.flush(testData);
    }
  });

  describe('When no httpInterceptor is configured', () => {
    it('pass through and do not have access tokens attached', fakeAsync((
      done: () => void
    ) => {
      config.httpInterceptor = (null as unknown) as HttpInterceptorConfig;
      assertPassThruApiCallTo('https://my-api.com/api/public', done);
    }));
  });

  describe('Requests that do not require authentication', () => {
    it('pass through and do not have access tokens attached', fakeAsync((
      done: () => void
    ) => {
      assertPassThruApiCallTo('https://my-api.com/api/public', done);
    }));
  });

  describe('Requests that are configured using a primitive', () => {
    it('attach the access token when the configuration uri is a string', fakeAsync((
      done: () => void
    ) => {
      // Testing /api/photos (exact match)
      assertAuthorizedApiCallTo('https://my-api.com/api/photos', done);
    }));

    it('attach the access token when the configuration uri is a string with a wildcard', fakeAsync((
      done: () => void
    ) => {
      // Testing /api/people* (wildcard match)
      assertAuthorizedApiCallTo('https://my-api.com/api/people/profile', done);
    }));

    it('matches a full url to an API', fakeAsync((done: () => void) => {
      // Testing 'https://my-api.com/orders' (exact)
      assertAuthorizedApiCallTo('https://my-api.com/orders', done);
    }));

    it('matches a URL that contains a query string', fakeAsync((
      done: () => void
    ) => {
      assertAuthorizedApiCallTo(
        'https://my-api.com/api/people?name=test',
        done
      );
    }));

    it('matches a URL that contains a hash fragment', fakeAsync((
      done: () => void
    ) => {
      assertAuthorizedApiCallTo(
        'https://my-api.com/api/people#hash-fragment',
        done
      );
    }));
  });

  describe('Requests that are configured using a complex object', () => {
    it('attach the access token when the uri is configured using a string', fakeAsync((
      done: () => void
    ) => {
      // Testing { uri: /api/orders } (exact match)
      assertAuthorizedApiCallTo('https://my-api.com/api/orders', done);
    }));

    it('pass through the route options to getTokenSilently, without additional properties', fakeAsync((
      done: () => void
    ) => {
      // Testing { uri: /api/addresses } (exact match)
      assertAuthorizedApiCallTo('https://my-api.com/api/addresses', done);

      expect(auth0Client.getTokenSilently).toHaveBeenCalledWith({
        audience: 'audience',
        scope: 'scope',
      });
    }));

    it('attach the access token when the configuration uri is a string with a wildcard', fakeAsync((
      done: () => void
    ) => {
      // Testing { uri: /api/calendar* } (wildcard match)
      assertAuthorizedApiCallTo('https://my-api.com/api/calendar/events', done);
    }));

    it('attaches the access token when the HTTP method matches', fakeAsync((
      done: () => void
    ) => {
      // Testing { uri: /api/register } (wildcard match)
      assertAuthorizedApiCallTo(
        'https://my-api.com/api/register',
        done,
        'post'
      );
    }));

    it('does not attach the access token if the HTTP method does not match', fakeAsync((
      done: () => void
    ) => {
      assertPassThruApiCallTo('https://my-api.com/api/public', done);
    }));

    it('does not execute HTTP call when not able to retrieve a token', fakeAsync((
      done: () => void
    ) => {
      (auth0Client.getTokenSilently as jasmine.Spy).and.returnValue(
        throwError({ error: 'login_required' })
      );

      httpClient.request('get', 'https://my-api.com/api/calendar').subscribe({
        error: (err) => expect(err).toEqual({ error: 'login_required' }),
      });

      httpTestingController.expectNone('https://my-api.com/api/calendar');
      flush();
    }));

    it('does execute HTTP call when not able to retrieve a token but allowAnonymous is set to true', fakeAsync((
      done: () => void
    ) => {
      (auth0Client.getTokenSilently as jasmine.Spy).and.returnValue(
        throwError({ error: 'login_required' })
      );

      assertPassThruApiCallTo('https://my-api.com/api/orders', done);
    }));

    it('emit error when not able to retrieve a token but allowAnonymous is set to false', fakeAsync((
      done: () => void
    ) => {
      (auth0Client.getTokenSilently as jasmine.Spy).and.callFake(() => {
        return Promise.reject({ error: 'login_required' });
      });

      httpClient.request('get', 'https://my-api.com/api/calendar').subscribe({
        error: (err) => expect(err).toEqual({ error: 'login_required' }),
      });

      httpTestingController.expectNone('https://my-api.com/api/calendar');
      flush();

      expect(authState.setError).toHaveBeenCalled();
    }));

    it('does not emit error when not able to retrieve a token but allowAnonymous is set to true', fakeAsync(() => {
      (auth0Client.getTokenSilently as jasmine.Spy).and.callFake(() => {
        return Promise.reject({ error: 'login_required' });
      });

      assertPassThruApiCallTo('https://my-api.com/api/orders', () => {
        expect(authState.setError).not.toHaveBeenCalled();
      });
    }));
  });

  describe('Requests that are configured using an uri matcher', () => {
    it('attach the access token when the matcher returns true', fakeAsync((
      done: () => void
    ) => {
      // Testing { uriMatcher: (uri) => uri.indexOf('/api/contact') !== -1 }
      assertAuthorizedApiCallTo('https://my-api.com/api/contact', done, 'post');
    }));

    it('pass through the route options to getTokenSilently, without additional properties', fakeAsync((
      done: () => void
    ) => {
      // Testing { uriMatcher: (uri) => uri.indexOf('/api/contact') !== -1 }
      assertAuthorizedApiCallTo('https://my-api.com/api/contact', done, 'post');

      expect(auth0Client.getTokenSilently).toHaveBeenCalledWith({
        audience: 'audience',
        scope: 'scope',
      });
    }));

    it('does not attach the access token when the HTTP method does not match', fakeAsync((
      done: () => void
    ) => {
      // Testing { uriMatcher: (uri) => uri.indexOf('/api/contact') !== -1 }
      assertAuthorizedApiCallTo('https://my-api.com/api/contact', done, 'post');
      assertPassThruApiCallTo('https://my-api.com/api/contact', done);
    }));
  });
});
Example #7
Source File: angular-context.spec.ts    From s-libs with MIT License 4 votes vote down vote up
describe('AngularContext', () => {
  class SnackBarContext extends AngularContext {
    constructor() {
      super({ imports: [MatSnackBarModule, NoopAnimationsModule] });
    }

    protected override cleanUp(): void {
      this.inject(OverlayContainer).ngOnDestroy();
      flush();
      super.cleanUp();
    }
  }

  describe('.getCurrent()', () => {
    it('returns the currently running angular context', () => {
      expect(AngularContext.getCurrent()).toBeUndefined();

      const ctx = new AngularContext();
      ctx.run(() => {
        expect(AngularContext.getCurrent()).toBe(ctx);
      });

      expect(AngularContext.getCurrent()).toBeUndefined();
    });
  });

  describe('.startTime', () => {
    it('controls the time at which the test starts', () => {
      const ctx = new AngularContext();
      ctx.startTime = new Date('2012-07-14T21:42:17.523Z');
      ctx.run(() => {
        expect(new Date()).toEqual(new Date('2012-07-14T21:42:17.523Z'));
      });
    });

    it('defaults to the current time', () => {
      const ctx = new AngularContext();
      const now = Date.now();
      ctx.run(() => {
        expect(Date.now()).toBeCloseTo(now, -1);
      });
    });
  });

  describe('constructor', () => {
    it('accepts module metadata to be bootstrapped', () => {
      const value = Symbol();
      const token = new InjectionToken<symbol>('tok');
      const ctx = new AngularContext({
        providers: [{ provide: token, useValue: value }],
      });
      ctx.run(() => {
        expect(ctx.inject(token)).toBe(value);
      });
    });

    it('sets up HttpClientTestingModule', () => {
      const ctx = new AngularContext();
      ctx.run(() => {
        expect(ctx.inject(HttpTestingController)).toBeDefined();
      });
    });

    it('sets up MockErrorHandler', () => {
      const ctx = new AngularContext();
      ctx.run(() => {
        expect(ctx.inject(ErrorHandler)).toEqual(jasmine.any(MockErrorHandler));
      });
    });

    it('gives a nice error message if trying to use 2 at the same time', () => {
      new AngularContext().run(async () => {
        expect(() => {
          // eslint-disable-next-line no-new -- nothing more is needed for this test
          new AngularContext();
        }).toThrowError(
          'There is already another AngularContext in use (or it was not cleaned up)',
        );
      });
    });
  });

  describe('.run()', () => {
    it('uses the fakeAsync zone', () => {
      const ctx = new AngularContext();
      ctx.run(() => {
        expect(tick).not.toThrow();
      });
    });

    it('can handle async tests that call tick', () => {
      let completed = false;
      const ctx = new AngularContext();
      ctx.run(async () => {
        await sleep(0);
        setTimeout(() => {
          completed = true;
        }, 500);
        ctx.tick(500);
      });
      expect(completed).toBeTrue();
    });

    it('does not swallow errors (production bug)', () => {
      expect(() => {
        new AngularContext().run(() => {
          throw new Error();
        });
      }).toThrowError();
    });
  });

  describe('.inject()', () => {
    it('fetches from the root injector', () => {
      const ctx = new AngularContext();
      ctx.run(() => {
        expect(ctx.inject(Injector)).toBe(TestBed.inject(Injector));
      });
    });
  });

  describe('.hasHarness()', () => {
    it('returns whether a match for the harness exists', () => {
      const ctx = new SnackBarContext();
      ctx.run(async () => {
        expect(await ctx.hasHarness(MatSnackBarHarness)).toBe(false);

        ctx.inject(MatSnackBar).open('hi');
        expect(await ctx.hasHarness(MatSnackBarHarness)).toBe(true);
      });
    });
  });

  describe('.getHarness()', () => {
    it('returns a harness', () => {
      const ctx = new SnackBarContext();
      ctx.run(async () => {
        ctx.inject(MatSnackBar).open('hi');
        const bar = await ctx.getHarness(MatSnackBarHarness);
        expect(await bar.getMessage()).toBe('hi');
      });
    });
  });

  describe('.getAllHarnesses()', () => {
    it('gets an array of harnesses', () => {
      const ctx = new SnackBarContext();
      ctx.run(async () => {
        let bars = await ctx.getAllHarnesses(MatSnackBarHarness);
        expect(bars.length).toBe(0);
        ctx.inject(MatSnackBar).open('hi');
        bars = await ctx.getAllHarnesses(MatSnackBarHarness);
        expect(bars.length).toBe(1);
        expect(await bars[0].getMessage()).toBe('hi');
      });
    });
  });

  describe('.tick()', () => {
    it('defaults to not advance time', () => {
      const ctx = new AngularContext();
      const start = ctx.startTime.getTime();
      ctx.run(() => {
        ctx.tick();
        expect(Date.now()).toBe(start);
      });
    });

    it('defaults to advancing in milliseconds', () => {
      const ctx = new AngularContext();
      const start = ctx.startTime.getTime();
      ctx.run(() => {
        ctx.tick(10);
        expect(Date.now()).toBe(start + 10);
      });
    });

    it('allows specifying the units to advance', () => {
      const ctx = new AngularContext();
      const start = ctx.startTime.getTime();
      ctx.run(() => {
        ctx.tick(10, 'sec');
        expect(Date.now()).toBe(start + 10000);
      });
    });

    it('runs change detection even if no tasks are queued', () => {
      let ranChangeDetection = false;

      @Component({ template: '' })
      class LocalComponent implements DoCheck {
        ngDoCheck(): void {
          ranChangeDetection = true;
        }
      }
      TestBed.overrideComponent(LocalComponent, {});

      const ctx = new AngularContext();
      ctx.run(() => {
        const resolver = ctx.inject(ComponentFactoryResolver);
        const factory = resolver.resolveComponentFactory(LocalComponent);
        const componentRef = factory.create(ctx.inject(Injector));
        ctx.inject(ApplicationRef).attachView(componentRef.hostView);

        expect(ranChangeDetection).toBe(false);
        ctx.tick();
        expect(ranChangeDetection).toBe(true);
      });
    });

    it('flushes micro tasks before running change detection', () => {
      let ranChangeDetection = false;
      let flushedMicroTasksBeforeChangeDetection = false;

      @Component({ template: '' })
      class LocalComponent implements DoCheck {
        ngDoCheck(): void {
          ranChangeDetection = true;
        }
      }
      TestBed.overrideComponent(LocalComponent, {});

      const ctx = new AngularContext();
      ctx.run(() => {
        const resolver = ctx.inject(ComponentFactoryResolver);
        const factory = resolver.resolveComponentFactory(LocalComponent);
        const componentRef = factory.create(ctx.inject(Injector));
        ctx.inject(ApplicationRef).attachView(componentRef.hostView);

        Promise.resolve().then(() => {
          flushedMicroTasksBeforeChangeDetection = !ranChangeDetection;
        });
        ctx.tick();
        expect(flushedMicroTasksBeforeChangeDetection).toBe(true);
      });
    });

    it('runs change detection after timeouts', () => {
      let ranTimeout = false;
      let ranChangeDetectionAfterTimeout = false;

      @Component({ template: '' })
      class LocalComponent implements DoCheck {
        ngDoCheck(): void {
          ranChangeDetectionAfterTimeout = ranTimeout;
        }
      }
      TestBed.overrideComponent(LocalComponent, {});

      const ctx = new AngularContext();
      ctx.run(() => {
        const resolver = ctx.inject(ComponentFactoryResolver);
        const factory = resolver.resolveComponentFactory(LocalComponent);
        const componentRef = factory.create(ctx.inject(Injector));
        ctx.inject(ApplicationRef).attachView(componentRef.hostView);

        setTimeout(() => {
          ranTimeout = true;
        });
        ctx.tick();
        expect(ranChangeDetectionAfterTimeout).toBe(true);
      });
    });

    it('advances `performance.now()`', () => {
      const ctx = new AngularContext();
      ctx.run(() => {
        const start = performance.now();
        ctx.tick(10);
        expect(performance.now()).toBe(start + 10);
      });
    });

    it('gives a nice error message when you try to use it outside `run()`', () => {
      const ctx = new AngularContext();
      expect(() => {
        ctx.tick();
      }).toThrowError(
        '.tick() only works inside the .run() callback (because it needs to be in a fakeAsync zone)',
      );
      ctx.run(noop);
    });
  });

  describe('.verifyPostTestConditions()', () => {
    it('errs if there are unexpected http requests', () => {
      const ctx = new AngularContext();
      expect(() => {
        ctx.run(() => {
          ctx.inject(HttpClient).get('an unexpected URL').subscribe();
        });
      }).toThrowError(
        'Expected no open requests, found 1: GET an unexpected URL',
      );
    });

    it('errs if there are unexpected errors', () => {
      @Component({ template: '<button (click)="throwError()"></button>' })
      class ThrowingComponent {
        throwError(): never {
          throw new Error();
        }
      }

      const ctx = new ComponentContext(ThrowingComponent);
      expect(() => {
        ctx.run(async () => {
          // TODO: make something like `ctx.getTestElement()`?
          const loader = FakeAsyncHarnessEnvironment.documentRootLoader(ctx);
          const button = await loader.locatorFor('button')();
          await button.click();
        });
      }).toThrowError('Expected no error(s), found 1');
    });
  });

  describe('.cleanUp()', () => {
    it('discards periodic tasks', () => {
      const ctx = new AngularContext();
      expect(() => {
        ctx.run(() => {
          setInterval(noop, 10);
        });
      })
        // No error: "1 periodic timer(s) still in the queue."
        .not.toThrowError();
    });

    it('flushes pending timeouts', () => {
      const ctx = new AngularContext();
      expect(() => {
        ctx.run(() => {
          setTimeout(noop, 1);
        });
      })
        // No error: "1 timer(s) still in the queue."
        .not.toThrowError();
    });
  });
});
Example #8
Source File: table.spec.ts    From ngx-gantt with MIT License 4 votes vote down vote up
describe('GanttTable', () => {
    let component: TestGanttTableComponent;
    let fixture: ComponentFixture<TestGanttTableComponent>;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            imports: [NgxGanttModule],
            declarations: [TestGanttTableComponent]
        }).compileComponents();
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(TestGanttTableComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

    it('should create gantt-table', () => {
        expect(component).toBeDefined();
        const ganttTable: DebugElement = fixture.debugElement.query(By.directive(GanttTableComponent));
        expect(ganttTable).toBeTruthy();
        expect(ganttTable.nativeElement).toBeTruthy();
    });

    it('should expand groups', () => {
        const ganttTable: DebugElement = fixture.debugElement.query(By.directive(GanttTableComponent));
        expect(ganttTable.query(By.css('.gantt-table-group-title')).nativeNode.classList.contains('expanded')).toBeTruthy();
        ganttTable.query(By.css('.gantt-table-group-title')).nativeNode.click();
        fixture.detectChanges();
        expect(ganttTable.query(By.css('.gantt-table-group-title')).nativeNode.classList.contains('expanded')).toBeFalsy();
    });

    it('should expand children', () => {
        const ganttTable: DebugElement = fixture.debugElement.query(By.directive(GanttTableComponent));
        const tableChildrenLength = ganttTable.query(By.css('.gantt-table-body')).children.length;
        ganttTable.nativeElement.querySelector('.gantt-table-item-with-group .gantt-expand-icon .expand-icon').click();
        fixture.detectChanges();
        expect(ganttTable.query(By.css('.gantt-table-body')).children.length).toEqual(tableChildrenLength + 1);
    });

    it('should column drag', fakeAsync(() => {
        const ganttTable: DebugElement = fixture.debugElement.query(By.directive(GanttTableComponent));
        const dragTrigger = ganttTable.nativeElement.querySelector('.gantt-table-header .gantt-table-column .gantt-table-drag-trigger');
        fixture.detectChanges();
        flush();

        const dragTriggerRight = dragTrigger.getBoundingClientRect().right;

        dispatchMouseEvent(dragTrigger, 'mousedown');
        fixture.detectChanges();
        flush();

        dispatchMouseEvent(document, 'mousemove', 200);
        fixture.detectChanges();
        flush();
        fixture.detectChanges();

        dispatchMouseEvent(document, 'mousemove', 250);
        fixture.detectChanges();
        flush();
        fixture.detectChanges();

        dispatchMouseEvent(document, 'mouseup');
        fixture.detectChanges();
        flush();

        expect(dragTrigger.getBoundingClientRect().right).not.toBe(dragTriggerRight);
    }));

    it('should table drag', fakeAsync(() => {
        const ganttTable: DebugElement = fixture.debugElement.query(By.directive(GanttTableComponent));
        const dragTrigger = ganttTable.nativeElement.children[2];
        fixture.detectChanges();

        const dragTriggerRight = dragTrigger.getBoundingClientRect().right;

        dispatchMouseEvent(dragTrigger, 'mousedown');
        fixture.detectChanges();
        flush();

        dispatchMouseEvent(document, 'mousemove', 250, 150);
        fixture.detectChanges();
        flush();
        fixture.detectChanges();

        dispatchMouseEvent(document, 'mousemove', 50, 50);
        fixture.detectChanges();
        flush();
        fixture.detectChanges();

        dispatchMouseEvent(document, 'mouseup');
        fixture.detectChanges();
        flush();

        expect(dragTrigger.getBoundingClientRect().left).not.toBe(dragTriggerRight);
    }));

    it('should active item when click item and selectable is true', fakeAsync(() => {
        const ganttTable: DebugElement = fixture.debugElement.query(By.directive(GanttTableComponent));
        const selectionModel = ganttTable.componentInstance.ganttUpper.selectionModel;
        const items = component.items;

        ganttTable.query(By.css('.gantt-table-item')).nativeNode.click();
        fixture.detectChanges();
        expect(selectionModel.hasValue()).toBeTrue();
        expect(selectionModel.selected[0]).toEqual(items[0].id);
    }));

    it('should has active class when click item and selectable is true', fakeAsync(() => {
        const ganttTable: DebugElement = fixture.debugElement.query(By.directive(GanttTableComponent));
        const ganttMain: DebugElement = fixture.debugElement.query(By.directive(GanttMainComponent));
        const itemNode = ganttTable.query(By.css('.gantt-table-item')).nativeNode;
        const mainItemNode = ganttMain.query(By.css('.gantt-item')).nativeNode;
        itemNode.click();
        fixture.detectChanges();
        expect(itemNode.classList).toContain('gantt-table-item-active');
        expect(mainItemNode.classList).toContain('gantt-main-item-active');
    }));

    it('should active two item when click two item and multiple is true', () => {
        const ganttTable: DebugElement = fixture.debugElement.query(By.directive(GanttTableComponent));
        const selectionModel = ganttTable.componentInstance.ganttUpper.selectionModel;
        const items = component.items;
        const itemNodes = ganttTable.queryAll(By.css('.gantt-table-item'));

        itemNodes[0].nativeNode.click();
        expect(selectionModel.selected.length).toEqual(1);
        itemNodes[1].nativeNode.click();
        expect(selectionModel.selected.length).toEqual(2);
        expect(selectionModel.selected.join(' ')).toEqual(
            items
                .slice(0, 2)
                .map((item) => item.id)
                .join(' ')
        );
        itemNodes[1].nativeNode.click();
        expect(selectionModel.selected.length).toEqual(1);
        expect(selectionModel.selected[0]).toEqual(items[0].id);
    });

    it('should active one item when multiple is false', () => {
        fixture.componentInstance.multiple = false;
        fixture.detectChanges();
        const ganttTable: DebugElement = fixture.debugElement.query(By.directive(GanttTableComponent));
        const selectionModel = ganttTable.componentInstance.ganttUpper.selectionModel;
        const items = component.items;
        const itemNodes = ganttTable.queryAll(By.css('.gantt-table-item'));
        itemNodes[0].nativeNode.click();
        expect(selectionModel.selected.length).toEqual(1);
        itemNodes[1].nativeNode.click();
        expect(selectionModel.selected.length).toEqual(1);
        expect(selectionModel.selected[0]).toEqual(items[1].id);
    });

    it('should toggle active one item when multiple is false and click same item', () => {
        fixture.componentInstance.multiple = false;
        fixture.detectChanges();
        const ganttTable: DebugElement = fixture.debugElement.query(By.directive(GanttTableComponent));
        const selectionModel = ganttTable.componentInstance.ganttUpper.selectionModel;
        const itemNode = ganttTable.query(By.css('.gantt-table-item')).nativeNode;
        itemNode.click();
        expect(selectionModel.selected.length).toEqual(1);
        itemNode.click();
        expect(selectionModel.selected.length).toEqual(0);
    });
});
Example #9
Source File: editable.component.spec.ts    From slate-angular with MIT License 4 votes vote down vote up
describe('Editable Component', () => {
    let component: AdvancedEditableComponent;
    let fixture: ComponentFixture<AdvancedEditableComponent>;

    beforeEach(fakeAsync(() => {
        configureBasicEditableTestingModule([AdvancedEditableComponent, TestingLeafComponent], [TestingLeafComponent]);
        fixture = TestBed.createComponent(AdvancedEditableComponent);
        component = fixture.componentInstance;
    }));    

    it('decorate', fakeAsync(() => {
        fixture.detectChanges();
        flush();
        fixture.detectChanges();
        let testingLeaf;
        testingLeaf= fixture.debugElement.query(By.css('.testing-leaf'));
        expect(testingLeaf).toBeFalsy();

        const keywords1 = 'text';
        component.generateDecorate(keywords1);
        fixture.detectChanges();
        flush();
        fixture.detectChanges();
        testingLeaf = fixture.debugElement.query(By.css('.testing-leaf')).nativeElement;
        expect(testingLeaf).toBeTruthy();
        expect(testingLeaf.textContent).toEqual(keywords1);

        const keywords2 = 'text';
        component.generateDecorate(keywords2);
        fixture.detectChanges();
        flush();
        fixture.detectChanges();
        testingLeaf = fixture.debugElement.query(By.css('.testing-leaf')).nativeElement;;
        expect(testingLeaf).toBeTruthy();
        expect(testingLeaf.textContent).toEqual(keywords2);
    }));

    it('should rerender when data reference changes', fakeAsync(() => {
        component.value = [
            {
                type: 'paragraph',
                children: [{ text: 'Stephen Curry' }],
                key: 'Curry'
            }
        ];
        fixture.detectChanges();
        flush();
        fixture.detectChanges();
        let paragraphElement = document.querySelector('[data-slate-node="element"]');
        component.value = [
            {
                type: 'paragraph',
                children: [{ text: 'Stephen Curry' }],
                key: 'Curry'
            }
        ];
        fixture.detectChanges();
        flush();
        fixture.detectChanges();
        let newParagraphElement = document.querySelector('[data-slate-node="element"]');
        expect(paragraphElement === newParagraphElement).toBeFalse();
    }));

    it('should not rerender when set trackBy', fakeAsync(() => {
        component.trackBy = (element) => {
            return element['key'];
        }
        component.value = [
            {
                type: 'paragraph',
                children: [{ text: 'Stephen Curry' }],
                key: 'Curry'
            }
        ];
        fixture.detectChanges();
        flush();
        fixture.detectChanges();
        let paragraphElement = document.querySelector('[data-slate-node="element"]');
        component.value = [
            {
                type: 'paragraph',
                children: [{ text: 'Stephen Curry' }],
                key: 'Curry'
            }
        ];
        fixture.detectChanges();
        flush();
        fixture.detectChanges();
        let newParagraphElement = document.querySelector('[data-slate-node="element"]');
        expect(paragraphElement === newParagraphElement).toBeTrue();
    }));

    it('should use default logic to show placeholder when set placeholder value',fakeAsync(()=> {
        const placeholder = 'hello world';
        component.placeholder = placeholder;
        component.value = [
            {
                type: 'paragraph',
                children: [{ text: '' }]
            }
        ];
        fixture.detectChanges();
        flush();
        fixture.detectChanges();
        const placeholderLeaf = document.querySelector('[data-slate-placeholder="true"]');
        expect(placeholderLeaf).not.toBeNull();
        
        AngularEditor.focus(component.editor);
        const inputElement = document.querySelector('[editable-text]');
        dispatchFakeEvent(inputElement, 'compositionstart', true);
        fixture.detectChanges();
        flush();
        fixture.detectChanges();
        let placeholderLeafWithComposition = document.querySelector('[data-slate-placeholder="true"]');
        expect(placeholderLeafWithComposition).toBeNull();
        
        // and disappear when editor has content
        component.value = [
            {
                type: 'paragraph',
                children: [{ text: 'input...' }]
            }
        ];
        fixture.detectChanges();
        flush();
        fixture.detectChanges();
        let placeholderLeafWithContent = document.querySelector('[data-slate-placeholder="true"]');
        expect(placeholderLeafWithContent).toBeNull();
    }))
});
Example #10
Source File: with-angular.spec.ts    From slate-angular with MIT License 4 votes vote down vote up
describe("with-angular", () => {
  let angularEditor: AngularEditor;
  function configEditor() {
    angularEditor = withAngular(createEditor());
    angularEditor.children = [
      {
        type: "paragraph",
        children: [
          { text: "This is editable " },
          { text: "rich" },
          { text: " text, " },
          { text: "much" },
          { text: " better than a " },
          { text: "<textarea>" },
          { text: "!" },
        ],
      },
    ];
  }
  beforeEach(() => {
    configEditor();
  });
  describe("onChange", () => {
    it("default onChange was called", fakeAsync(() => {
      spyOn(angularEditor, "onChange").and.callThrough();
      Transforms.select(angularEditor, {
        anchor: {
          path: [0, 0],
          offset: 0,
        },
        focus: {
          path: [0, 0],
          offset: 3,
        },
      });
      flush();
      expect(angularEditor.onChange).toHaveBeenCalled();
    }));
    it("custom onChange was called", fakeAsync(() => {
      let isOnChanged = false;
      EDITOR_TO_ON_CHANGE.set(angularEditor, () => {
        isOnChanged = true;
      });
      Transforms.select(angularEditor, {
        anchor: {
          path: [0, 0],
          offset: 0,
        },
        focus: {
          path: [0, 0],
          offset: 3,
        },
      });
      flush();
      expect(isOnChanged).toBeTruthy();
    }));
  });

  describe('apply', () => {
    let component: BasicEditableComponent;
    let fixture: ComponentFixture<BasicEditableComponent>;

    beforeEach(fakeAsync(() => {
      configureBasicEditableTestingModule([BasicEditableComponent]);
      fixture = TestBed.createComponent(BasicEditableComponent);
      component = fixture.componentInstance;
      component.value = [
        { type: 'paragraph', children: [{ text: 'first text!' }] },
        {
          type: "table",
          children: [
            {
              type: "table-row",
              children: [
                {
                  type: "table-cell",
                  children: [
                    {
                      type: 'paragraph',
                      children: [{ text: '1!' }]
                    },
                    {
                      type: 'paragraph',
                      children: [{ text: '2!' }]
                    }
                  ]
                },
                {
                  type: "table-cell",
                  children: [
                    {
                      type: 'paragraph',
                      children: [{ text: '3!' }]
                    },
                    {
                      type: 'paragraph',
                      children: [{ text: '4!' }]
                    }
                  ]
                },
              ],
            },
            {
              type: "table-row",
              children: [
                {
                  type: "table-cell",
                  children: [
                    {
                      type: 'paragraph',
                      children: [{ text: '5!' }]
                    },
                    {
                      type: 'paragraph',
                      children: [{ text: '6!' }]
                    }
                  ]
                },
                {
                  type: "table-cell",
                  children: [
                    {
                      type: 'paragraph',
                      children: [{ text: '7!' }]
                    },
                    {
                      type: 'paragraph',
                      children: [{ text: '8!' }]
                    }
                  ]
                },
              ],
            },
          ],
        },
        {
          type: "table",
          children: [
            {
              type: "table-row",
              children: [
                {
                  type: "table-cell",
                  children: [
                    {
                      type: 'paragraph',
                      children: [{ text: '1!' }]
                    },
                    {
                      type: 'paragraph',
                      children: [{ text: '2!' }]
                    }
                  ]
                },
                {
                  type: "table-cell",
                  children: [
                    {
                      type: 'paragraph',
                      children: [{ text: '3!' }]
                    },
                    {
                      type: 'paragraph',
                      children: [{ text: '4!' }]
                    }
                  ]
                },
              ],
            },
            {
              type: "table-row",
              children: [
                {
                  type: "table-cell",
                  children: [
                    {
                      type: 'paragraph',
                      children: [{ text: '5!' }]
                    },
                    {
                      type: 'paragraph',
                      children: [{ text: '6!' }]
                    }
                  ]
                },
                {
                  type: "table-cell",
                  children: [
                    {
                      type: 'paragraph',
                      children: [{ text: '7!' }]
                    },
                    {
                      type: 'paragraph',
                      children: [{ text: '8!' }]
                    }
                  ]
                },
              ],
            },
          ],
        },
        { type: 'paragraph', children: [{ text: 'last text!' }] }
      ];
      fixture.detectChanges();
      flush();
      fixture.detectChanges();
    }));

    afterEach(() => {
      fixture.destroy();
    });

    it('move node to sibling when there have a common parent', fakeAsync(() => {
      const oldPath = [1,0,0,0];
      const newPath = [1,0,0,1];
      const tablePath = [1];
      const tableRowPath = [1, 0];
      const tableCellPath = [1, 0, 0];
      const tableNode = Node.get(component.editor, tablePath);
      const tableRowNode = Node.get(component.editor, tableRowPath);
      const tableCellNode = Node.get(component.editor, tableCellPath);
      Transforms.moveNodes(component.editor, {
        at: oldPath,
        to: newPath,
      });
      tick(100);
      const newTableNode = Node.get(component.editor, tablePath);
      const newTableRowNode = Node.get(component.editor, tableRowPath);
      const newTableCellNode = Node.get(component.editor, tableCellPath);
      expect(tableNode).not.toEqual(newTableNode);
      validKey(tableNode, newTableNode);
      expect(tableRowNode).not.toEqual(newTableRowNode);
      validKey(tableRowNode, newTableRowNode);
      expect(tableCellNode).not.toEqual(newTableCellNode);
      validKey(tableCellNode, newTableCellNode);
    }));

    it('move node to sibling when there is no common parent', fakeAsync(() => {
      const oldPath = [1,0,0,0];
      const newPath = [2,0,0,1];

      const tablePath = [1];
      const tableRowPath = [1, 0];
      const tableCellPath = [1, 0, 0];
      const tableNode = Node.get(component.editor, tablePath);
      const tableRowNode = Node.get(component.editor, tableRowPath);
      const tableCellNode = Node.get(component.editor, tableCellPath);

      const tablePath2 = [2];
      const tableRowPath2 = [2, 0];
      const tableCellPath2 = [2, 0, 0];
      const tableNode2 = Node.get(component.editor, tablePath2);
      const tableRowNode2 = Node.get(component.editor, tableRowPath2);
      const tableCellNode2 = Node.get(component.editor, tableCellPath2);

      Transforms.moveNodes(component.editor, {
        at: oldPath,
        to: newPath,
      });
      tick(100);

      // valid move origin
      const newTableNode = Node.get(component.editor, tablePath);
      const newTableRowNode = Node.get(component.editor, tableRowPath);
      const newTableCellNode = Node.get(component.editor, tableCellPath);
      expect(tableNode).not.toEqual(newTableNode);
      validKey(tableNode, newTableNode);
      expect(tableRowNode).not.toEqual(newTableRowNode);
      validKey(tableRowNode, newTableRowNode);
      expect(tableCellNode).not.toEqual(newTableCellNode);
      validKey(tableCellNode, newTableCellNode);

      // valid move targit
      const newTableNode2 = Node.get(component.editor, tablePath2);
      const newTableRowNode2 = Node.get(component.editor, tableRowPath2);
      const newTableCellNode2 = Node.get(component.editor, tableCellPath2);
      expect(tableNode2).not.toEqual(newTableNode2);
      validKey(tableNode2, newTableNode2);
      expect(tableRowNode2).not.toEqual(newTableRowNode2);
      validKey(tableRowNode2, newTableRowNode2);
      expect(tableCellNode2).not.toEqual(newTableCellNode2);
      validKey(tableCellNode2, newTableCellNode2);
    }));

    it('can correctly insert the list in the last row', fakeAsync(() => {
      Transforms.select(component.editor, Editor.end(component.editor, [3]));
      component.editor.insertBreak();
      Transforms.wrapNodes(
        component.editor,
        { type: 'list-item', children: [] },
        {
            at: [4],
            split: true
        }
      );
      Transforms.wrapNodes(component.editor, { type: 'numbered-list', children: [] } as any, {
        at: [4, 0, 0],
        match: node => Element.isElement(node) && node.type === 'list-item'
      });

      expect(component.editor.children.length).toBe(5);
      expect((component.editor.children[4] as any).type).toBe('numbered-list');
    }));
  })
});