Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/core/src/application/application_tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ export const APP_ID = new InjectionToken<string>(
/** Default value of the `APP_ID` token. */
const DEFAULT_APP_ID = 'ng';

/**
* Internal token that indicates whether the application is running in a test environment (e.g. TestBed).
*/
export const IS_TESTING = new InjectionToken<boolean>(
typeof ngDevMode !== 'undefined' && ngDevMode ? 'IS_TESTING' : '',
{
factory: () => false,
},
);

/** Initializer check for the validity of the APP_ID */
export const validAppIdInitializer: StaticProvider = {
provide: ENVIRONMENT_INITIALIZER,
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/core_private_export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export {
IMAGE_CONFIG as ɵIMAGE_CONFIG,
IMAGE_CONFIG_DEFAULTS as ɵIMAGE_CONFIG_DEFAULTS,
ImageConfig as ɵImageConfig,
IS_TESTING as ɵIS_TESTING,
} from './application/application_tokens';
export {internalCreateApplication as ɵinternalCreateApplication} from './application/create_application';
export {
Expand Down
7 changes: 6 additions & 1 deletion packages/core/src/defer/instructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

import {setActiveConsumer} from '../../primitives/signals';
import {IS_TESTING} from '../application/application_tokens';

import {
DEFER_BLOCK_ID,
Expand Down Expand Up @@ -148,7 +149,11 @@ export function ɵɵdefer(
if (typeof ngHmrMode !== 'undefined' && ngHmrMode) {
logHmrWarning(injector);
}
if (hasHydrateTriggers(flags) && !incrementalHydrationEnabled) {
if (
hasHydrateTriggers(flags) &&
!incrementalHydrationEnabled &&
!injector.get(IS_TESTING, false)
) {
warnIncrementalHydrationNotConfigured();
}
}
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/hydration/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

import {APP_BOOTSTRAP_LISTENER, ApplicationRef} from '../application/application_ref';
import {IS_TESTING} from '../application/application_tokens';
import {Console} from '../console';
import {
ENVIRONMENT_INITIALIZER,
Expand Down Expand Up @@ -230,6 +231,7 @@ export function withDomHydration(): EnvironmentProviders {
} else if (
typeof ngDevMode !== 'undefined' &&
ngDevMode &&
!inject(IS_TESTING) &&
!isClientRenderModeEnabled(doc)
) {
const console = inject(Console);
Expand Down
2 changes: 2 additions & 0 deletions packages/core/testing/src/test_bed_compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import {ResourceLoader} from '@angular/compiler';
import {
ɵANIMATIONS_DISABLED as ANIMATIONS_DISABLED,
ɵIS_TESTING as IS_TESTING,
ApplicationInitStatus,
ɵcompileComponent as compileComponent,
ɵcompileDirective as compileDirective,
Expand Down Expand Up @@ -995,6 +996,7 @@ export class TestBedCompiler {
provide: ANIMATIONS_DISABLED,
useValue: !this.animationsEnabled,
},
{provide: IS_TESTING, useValue: true},
{
provide: INTERNAL_APPLICATION_ERROR_HANDLER,
useFactory: () => {
Expand Down
52 changes: 52 additions & 0 deletions packages/platform-browser/test/hydration_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
Component,
Injectable,
PLATFORM_ID,
ɵIS_TESTING as IS_TESTING,
ɵresetIncrementalHydrationEnabledWarnedForTests as resetIncrementalHydrationEnabledWarnedForTests,
ɵSSR_CONTENT_INTEGRITY_MARKER as SSR_CONTENT_INTEGRITY_MARKER,
} from '@angular/core';
import {TestBed} from '@angular/core/testing';
Expand Down Expand Up @@ -173,4 +175,54 @@ describe('provideClientHydration', () => {
}).toThrowError(/Configuration error: found both withIncrementalHydration/);
});
});

describe('in TestBed', () => {
beforeEach(() => {
globalThis['ngServerMode'] = undefined;
});

it('should not log NG0505 warning when provideClientHydration is used in TestBed', () => {
const consoleSpy = spyOn(console, 'warn');
TestBed.resetTestingModule();
TestBed.configureTestingModule({
providers: [provideClientHydration()],
});
TestBed.createComponent(SomeComponent);
expect(consoleSpy).not.toHaveBeenCalledWith(
jasmine.stringMatching('NG0505: Angular hydration was requested on the client'),
);
});

it('should not log NG0508 warning when defer block with hydrate triggers is used in TestBed without hydration providers', () => {
resetIncrementalHydrationEnabledWarnedForTests();
@Component({
template: `
@defer (hydrate on idle) {
<p>Defer hydrated</p>
}
`,
})
class DeferHydrateComponent {}

const consoleSpy = spyOn(console, 'warn');
TestBed.resetTestingModule();
TestBed.configureTestingModule({
imports: [DeferHydrateComponent],
});
TestBed.createComponent(DeferHydrateComponent);
expect(consoleSpy).not.toHaveBeenCalledWith(jasmine.stringMatching('NG0508'));
});

it('should log NG0505 warning if IS_TESTING is explicitly false and no serialized info is present', () => {
const consoleSpy = spyOn(console, 'warn');
TestBed.resetTestingModule();
TestBed.configureTestingModule({
providers: [provideClientHydration(), {provide: IS_TESTING, useValue: false}],
});
TestBed.createComponent(SomeComponent);
expect(consoleSpy).toHaveBeenCalledWith(
jasmine.stringMatching('NG0505: Angular hydration was requested on the client'),
);
});
});
});
10 changes: 9 additions & 1 deletion packages/platform-browser/testing/src/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@
* found in the LICENSE file at https://angular.dev/license
*/
import {ɵprovideFakePlatformNavigation} from '@angular/common/testing';
import {APP_ID, createPlatformFactory, NgModule, StaticProvider, PlatformRef} from '@angular/core';
import {
APP_ID,
createPlatformFactory,
NgModule,
StaticProvider,
PlatformRef,
ɵIS_TESTING as IS_TESTING,
} from '@angular/core';
import {TestComponentRenderer} from '@angular/core/testing';
// g3-only import {BrowserModule, platformBrowser} from '@angular/platform-browser';
import {BrowserModule, platformBrowser} from '../../index'; // 3p-only
Expand All @@ -29,6 +36,7 @@ export const platformBrowserTesting: (extraProviders?: StaticProvider[]) => Plat
exports: [BrowserModule],
providers: [
{provide: APP_ID, useValue: 'a'},
{provide: IS_TESTING, useValue: true},
ɵprovideFakePlatformNavigation(),
{provide: TestComponentRenderer, useClass: DOMTestComponentRenderer},
],
Expand Down
Loading