Raw File
view_transitions.spec.ts
/**
 * @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
 */

import {DOCUMENT} from '@angular/common';
import {Component, destroyPlatform, inject} from '@angular/core';
import {bootstrapApplication} from '@angular/platform-browser';
import {withBody} from '@angular/private/testing';
import {Event, NavigationEnd, provideRouter, Router, withDisabledInitialNavigation, withViewTransitions} from '@angular/router';


describe('view transitions', () => {
  if (isNode) {
    it('are not available in node environment', () => {});
    return;
  }

  beforeEach(destroyPlatform);
  afterEach(destroyPlatform);

  @Component({
    selector: 'test-app',
    standalone: true,
    template: ``,
  })
  class App {
  }
  beforeEach(withBody('<test-app></test-app>', () => {}));
  it('should skip initial transition', async () => {
    const appRef = await bootstrapApplication(App, {
      providers: [provideRouter(
          [{path: '**', component: App}],
          withDisabledInitialNavigation(),
          withViewTransitions({skipInitialTransition: true}),
          )]
    });

    const doc = appRef.injector.get(DOCUMENT);
    if (!doc.startViewTransition) {
      return;
    }

    const viewTransitionSpy = spyOn(doc, 'startViewTransition').and.callThrough();
    await appRef.injector.get(Router).navigateByUrl('/a');
    expect(viewTransitionSpy).not.toHaveBeenCalled();
    await appRef.injector.get(Router).navigateByUrl('/b');
    expect(viewTransitionSpy).toHaveBeenCalled();
  });

  it('should have the correct event order when using view transitions', async () => {
    @Component({
      selector: 'component-b',
      template: `b`,
      standalone: true,
    })
    class ComponentB {
    }


    const res = await bootstrapApplication(
        App,
        {providers: [provideRouter([{path: 'b', component: ComponentB}], withViewTransitions())]});
    const router = res.injector.get(Router);
    const eventLog = [] as Event[];
    router.events.subscribe(e => {
      eventLog.push(e);
    });

    await router.navigateByUrl('/b');
    expect(eventLog[eventLog.length - 1]).toBeInstanceOf(NavigationEnd);
  });

  describe('onViewTransitionCreated option', () => {
    it('should not create a view transition if only the fragment changes', async () => {
      @Component({
        selector: 'test-app',
        standalone: true,
        template: `{{checks}}`,
      })
      class App {
        checks = 0;
        ngDoCheck() {
          this.checks++;
        }
      }

      const transitionSpy = jasmine.createSpy();
      const appRef = await bootstrapApplication(App, {
        providers: [provideRouter(
            [{path: '**', component: App}],
            withDisabledInitialNavigation(),
            withViewTransitions({onViewTransitionCreated: transitionSpy}),
            )]
      });

      const doc = appRef.injector.get(DOCUMENT);
      if (!doc.startViewTransition) {
        return;
      }

      await appRef.injector.get(Router).navigateByUrl('/a');
      expect(transitionSpy).toHaveBeenCalled();
    });
  });
});
back to top