create method

Future<NgTestFixture<T>> create({
  1. FutureOr<void> beforeComponentCreated(
    1. Injector
    )?,
  2. FutureOr<void> beforeChangeDetection(
    1. T instance
    )?,
})

Creates a new test application with T as the root component.

If beforeChangeDetection is set, it is called before any initial change detection (so you can do initialization of component state that might be required).

Returns a future that completes with a fixture around the component.

Implementation

Future<NgTestFixture<T>> create({
  FutureOr<void> Function(Injector)? beforeComponentCreated,
  FutureOr<void> Function(T instance)? beforeChangeDetection,
}) {
  // We *purposefully* do not use async/await here - that always adds an
  // additional micro-task - we want this to fail fast without entering an
  // asynchronous event if another test is running.
  _checkForActiveTest();

  // Future.sync promotes synchronous errors to Future.error if they occur.
  return Future<NgTestFixture<T>>.sync(() {
    // Ensure that no tests have started since the last microtask.
    _checkForActiveTest();

    // Create a zone to intercept timer creation.
    final timerHookZone = TimerHookZone();
    late final NgZone ngZoneInstance;
    NgZone ngZoneFactory() {
      return timerHookZone.run(() {
        return ngZoneInstance = NgZone();
      });
    }

    // Created within "createStabilizersAndRunUserHook".
    late final NgTestStabilizer allStabilizers;

    Future<void> createStabilizersAndRunUserHook(Injector injector) async {
      // Some internal stabilizers get access to the TimerHookZone.
      // Most (i.e. user-land) stabilizers do not.
      final createStabilizer = _createStabilizer;
      allStabilizers = createStabilizer is AllowTimerHookZoneAccess
          ? createStabilizer(injector, timerHookZone)
          : createStabilizer(injector);

      // If there is no user hook, we are done.
      if (beforeComponentCreated == null) {
        return;
      }

      // If there is a user hook, execute it within the ngZone:
      final completer = Completer<void>();
      ngZoneInstance.runGuarded(() async {
        try {
          await beforeComponentCreated(injector);
          completer.complete();
        } catch (e, s) {
          completer.completeError(e, s);
        }
      });
      return completer.future.whenComplete(() => allStabilizers.update());
    }

    return bootstrapForTest<T>(
      _componentFactory,
      _host ?? _defaultHost(),
      _rootInjector,
      beforeComponentCreated: createStabilizersAndRunUserHook,
      beforeChangeDetection: beforeChangeDetection,
      createNgZone: ngZoneFactory,
    ).then((componentRef) async {
      _checkForActiveTest();
      await allStabilizers.stabilize();
      final testFixture = NgTestFixture(
        componentRef.injector.provideType(ApplicationRef),
        componentRef,
        allStabilizers,
      );
      // We need the local variable to capture the generic type T.
      activeTest = testFixture;
      return testFixture;
    });
  });
}