/**
 * @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 {Component, destroyPlatform, NgModule, Pipe, PipeTransform} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {withBody} from '@angular/private/testing';

describe('NgModule scopes', () => {
  beforeEach(destroyPlatform);
  afterEach(destroyPlatform);

  it(
    'should apply NgModule scope to a component that extends another component class',
    withBody('<my-app></my-app>', async () => {
      // Regression test for https://github.com/angular/angular/issues/37105
      //
      // This test reproduces a scenario that used to fail due to a reentrancy issue in Ivy's JIT
      // compiler. Extending a component from a decorated baseclass would inadvertently compile
      // the subclass twice. NgModule scope information would only be present on the initial
      // compilation, but then overwritten during the second compilation. This meant that the
      // baseclass did not have a NgModule scope, such that declarations are not available.
      //
      // The scenario cannot be tested using TestBed as it influences how NgModule
      // scopes are applied, preventing the issue from occurring.

      @Pipe({name: 'multiply'})
      class MultiplyPipe implements PipeTransform {
        transform(value: number, factor: number): number {
          return value * factor;
        }
      }

      @Component({template: '...'})
      class BaseComponent {}

      @Component({selector: 'my-app', template: 'App - {{ 3 | multiply:2 }}'})
      class App extends BaseComponent {}

      @NgModule({
        imports: [BrowserModule],
        declarations: [App, BaseComponent, MultiplyPipe],
        bootstrap: [App],
      })
      class Mod {}

      const ngModuleRef = await platformBrowserDynamic().bootstrapModule(Mod);
      expect(document.body.textContent).toContain('App - 6');
      ngModuleRef.destroy();
    }),
  );
});
