diff --git a/packages/core/src/hydration/api.ts b/packages/core/src/hydration/api.ts
index e6272d6eae4..53faf67b841 100644
--- a/packages/core/src/hydration/api.ts
+++ b/packages/core/src/hydration/api.ts
@@ -29,12 +29,21 @@ import {performanceMarkFeature} from '../util/performance';
import {NgZone} from '../zone';
import {withEventReplay} from './event_replay';
+import {
+ ChangeDetectionScheduler,
+ NotificationSource,
+} from '../change_detection/scheduling/zoneless_scheduling';
+import {DEHYDRATED_BLOCK_REGISTRY, DehydratedBlockRegistry} from '../defer/registry';
+import {processAndInitTriggers} from '../defer/triggering';
+import {DOCUMENT} from '../document';
+import {DOC_PAGE_BASE_URL} from '../error_details_base_url';
import {cleanupDehydratedViews} from './cleanup';
import {
enableClaimDehydratedIcuCaseImpl,
enablePrepareI18nBlockForHydrationImpl,
setIsI18nHydrationSupportEnabled,
} from './i18n';
+import {gatherDeferBlocksCommentNodes} from './node_lookup_utils';
import {
IS_HYDRATION_DOM_REUSE_ENABLED,
IS_I18N_HYDRATION_ENABLED,
@@ -52,11 +61,6 @@ import {
verifySsrContentsIntegrity,
} from './utils';
import {enableFindMatchingDehydratedViewImpl} from './views';
-import {DEHYDRATED_BLOCK_REGISTRY, DehydratedBlockRegistry} from '../defer/registry';
-import {gatherDeferBlocksCommentNodes} from './node_lookup_utils';
-import {processAndInitTriggers} from '../defer/triggering';
-import {DOCUMENT} from '../document';
-import {DOC_PAGE_BASE_URL} from '../error_details_base_url';
/**
* Indicates whether the hydration-related code was added,
@@ -277,6 +281,7 @@ export function withDomHydration(): EnvironmentProviders {
{
provide: APP_BOOTSTRAP_LISTENER,
useFactory: () => {
+ const scheduler = inject(ChangeDetectionScheduler);
if (inject(IS_HYDRATION_DOM_REUSE_ENABLED)) {
const appRef = inject(ApplicationRef);
@@ -304,6 +309,8 @@ export function withDomHydration(): EnvironmentProviders {
countBlocksSkippedByHydration(appRef.injector);
printHydrationStats(appRef.injector);
}
+ // We need to schedule the execution of the render hooks because the hydration cleanup alters the DOM.
+ scheduler.notify(NotificationSource.RenderHook);
});
};
}
diff --git a/packages/platform-server/test/BUILD.bazel b/packages/platform-server/test/BUILD.bazel
index 0556143d2b7..7ba9e979242 100644
--- a/packages/platform-server/test/BUILD.bazel
+++ b/packages/platform-server/test/BUILD.bazel
@@ -1,4 +1,4 @@
-load("//tools:defaults.bzl", "angular_jasmine_test", "ts_project")
+load("//tools:defaults.bzl", "angular_jasmine_test", "ts_project", "zoneless_jasmine_test")
ts_project(
name = "dom_utils",
@@ -65,6 +65,7 @@ ts_project(
],
)
+# This target is meant to run with Zone.js as some test cases are shared between Zone & Zoneless.
angular_jasmine_test(
name = "test",
data = [
@@ -73,7 +74,7 @@ angular_jasmine_test(
],
)
-angular_jasmine_test(
+zoneless_jasmine_test(
name = "event_replay_test",
data = [
":event_replay_test_lib",
diff --git a/packages/platform-server/test/full_app_hydration_spec.ts b/packages/platform-server/test/full_app_hydration_spec.ts
index 1c70be62f08..37042e5e690 100644
--- a/packages/platform-server/test/full_app_hydration_spec.ts
+++ b/packages/platform-server/test/full_app_hydration_spec.ts
@@ -46,8 +46,8 @@ import {
PLATFORM_ID,
Provider,
provideZoneChangeDetection,
- provideZonelessChangeDetection,
QueryList,
+ signal,
TemplateRef,
ViewChild,
ViewContainerRef,
@@ -2821,9 +2821,9 @@ describe('platform-server full application hydration integration', () => {
selector: 'app',
imports: [MyLazyCmp],
template: `
- Visible: {{ isVisible }}.
+ Visible: {{ isVisible() }}.
- @defer (when isVisible) {
+ @defer (when isVisible()) {
} @loading {
Loading...
@@ -2835,19 +2835,21 @@ describe('platform-server full application hydration integration', () => {
`,
})
class SimpleComponent {
- isVisible = false;
+ isVisible = signal(false);
+ pendingTasks = inject(PendingTasks);
ngOnInit() {
+ const removeTask = this.pendingTasks.add();
setTimeout(() => {
// This changes the triggering condition of the defer block,
// but it should be ignored and the placeholder content should be visible.
- this.isVisible = true;
+ this.isVisible.set(true);
+ removeTask();
});
}
}
- const envProviders = [provideZoneChangeDetection() as any];
- const html = await ssr(SimpleComponent, {envProviders});
+ const html = await ssr(SimpleComponent);
const ssrContents = getAppContents(html);
expect(ssrContents).toContain(' {
resetTViewsFor(SimpleComponent);
- const appRef = await prepareEnvironmentAndHydrate(doc, html, SimpleComponent, {
- envProviders,
- });
+ const appRef = await prepareEnvironmentAndHydrate(doc, html, SimpleComponent);
const compRef = getComponentRef(appRef);
appRef.tick();
@@ -4591,103 +4591,129 @@ describe('platform-server full application hydration integration', () => {
expect(clientContents).not.toContain('This is a SERVER-ONLY content');
});
- it('should trigger change detection after cleanup (immediate)', async () => {
- const observedChildCountLog: number[] = [];
+ [true, false].forEach((zoneless) => {
+ it(`should trigger ${zoneless ? 'zoneless' : 'zone'} change detection after cleanup (immediate)`, async () => {
+ const observedChildCountLog: number[] = [];
- @Component({
- selector: 'app',
- imports: [NgIf],
- template: `
- This is a SERVER-ONLY content
- This is a CLIENT-ONLY content
- `,
- })
- class SimpleComponent {
- isServer = isPlatformServer(inject(PLATFORM_ID));
- elementRef = inject(ElementRef);
+ @Component({
+ selector: 'app',
+ imports: [NgIf],
+ template: `
+ This is a SERVER-ONLY content
+ This is a CLIENT-ONLY content
+ `,
+ })
+ class SimpleComponent {
+ isServer = isPlatformServer(inject(PLATFORM_ID));
+ elementRef = inject(ElementRef);
- constructor() {
- afterEveryRender(() => {
- observedChildCountLog.push(this.elementRef.nativeElement.childElementCount);
- });
+ constructor() {
+ afterEveryRender(() => {
+ observedChildCountLog.push(this.elementRef.nativeElement.childElementCount);
+ });
+ }
}
- }
- const envProviders = [provideZoneChangeDetection() as any];
- const html = await ssr(SimpleComponent, {envProviders});
- let ssrContents = getAppContents(html);
+ const envProviders = zoneless ? [] : [provideZoneChangeDetection() as any];
+ const html = await ssr(SimpleComponent, {envProviders});
+ let ssrContents = getAppContents(html);
- expect(ssrContents).toContain(' {
- const observedChildCountLog: number[] = [];
-
- @Component({
- selector: 'app',
- imports: [NgIf],
- template: `
- This is a SERVER-ONLY content
- This is a CLIENT-ONLY content
- `,
- })
- class SimpleComponent {
- isServer = isPlatformServer(inject(PLATFORM_ID));
- elementRef = inject(ElementRef);
-
- constructor() {
- afterEveryRender(() => {
- observedChildCountLog.push(this.elementRef.nativeElement.childElementCount);
- });
-
- // Create a dummy promise to prevent stabilization
- new Promise((resolve) => {
- setTimeout(resolve, 0);
- });
+ if (zoneless) {
+ // 1.) Bootstrap
+ // 2.) After cleanup
+ expect(observedChildCountLog).toEqual([2, 1]);
+ } else {
+ // afterRender should be triggered by:
+ // 1.) Bootstrap
+ // 2.) Microtask empty event
+ // 3.) Stabilization + cleanup
+ expect(observedChildCountLog).toEqual([2, 2, 1]);
}
- }
-
- const envProviders = [provideZoneChangeDetection() as any];
- const html = await ssr(SimpleComponent, {envProviders});
- let ssrContents = getAppContents(html);
-
- expect(ssrContents).toContain(' {
+ const observedChildCountLog: number[] = [];
- await appRef.whenStable();
+ @Component({
+ selector: 'app',
+ imports: [NgIf],
+ template: `
+ This is a SERVER-ONLY content
+ This is a CLIENT-ONLY content
+ `,
+ })
+ class SimpleComponent {
+ isServer = isPlatformServer(inject(PLATFORM_ID));
+ elementRef = inject(ElementRef);
- // afterRender should be triggered by:
- // 3.) Microtask empty event
- // 4.) Stabilization + cleanup
- expect(observedChildCountLog).toEqual([2, 2, 2, 1]);
+ constructor() {
+ afterEveryRender(() => {
+ observedChildCountLog.push(this.elementRef.nativeElement.childElementCount);
+ });
+
+ // Create a dummy promise to prevent stabilization
+ inject(PendingTasks).run(
+ async () =>
+ await new Promise((resolve) => {
+ setTimeout(resolve, 0);
+ }),
+ );
+ }
+ }
+
+ const envProviders = zoneless ? [] : [provideZoneChangeDetection() as any];
+ const html = await ssr(SimpleComponent, {envProviders});
+ let ssrContents = getAppContents(html);
+
+ expect(ssrContents).toContain(' {
// and the server: we use it to test the logic to cleanup
// dehydrated views.
isServer = isPlatformServer(inject(PLATFORM_ID));
+ pendingTasks = inject(PendingTasks);
ngOnInit() {
- setTimeout(() => {}, 100);
+ const remove = this.pendingTasks.add();
+ setTimeout(() => {
+ remove();
+ }, 100);
}
}
- const envProviders = [provideZoneChangeDetection() as any];
- const html = await ssr(SimpleComponent, {envProviders});
+ const html = await ssr(SimpleComponent);
let ssrContents = getAppContents(html);
expect(ssrContents).toContain(' {
expect(ssrContents).toContain('This is NgSwitch SERVER-ONLY content');
resetTViewsFor(SimpleComponent);
- const appRef = await prepareEnvironmentAndHydrate(doc, html, SimpleComponent, {
- envProviders,
- });
+ const appRef = await prepareEnvironmentAndHydrate(doc, html, SimpleComponent);
const compRef = getComponentRef(appRef);
appRef.tick();
@@ -7629,46 +7656,6 @@ describe('platform-server full application hydration integration', () => {
});
});
- describe('zoneless', () => {
- it('should not produce "unsupported configuration" warnings for zoneless mode', async () => {
- @Component({
- selector: 'app',
- template: `
-
-
- `,
- })
- class SimpleComponent {}
-
- const html = await ssr(SimpleComponent);
- const ssrContents = getAppContents(html);
-
- expect(ssrContents).toContain(`(appRef);
- appRef.tick();
-
- // Make sure there are no extra logs in case zoneless mode is enabled.
- verifyHasNoLog(
- appRef,
- 'NG05000: Angular detected that hydration was enabled for an application ' +
- 'that uses a custom or a noop Zone.js implementation.',
- );
-
- const clientRootNode = compRef.location.nativeElement;
- verifyAllNodesClaimedForHydration(clientRootNode);
- verifyClientAndSSRContentsMatch(ssrContents, clientRootNode);
- });
- });
-
describe('Router', () => {
it('should wait for lazy routes before triggering post-hydration cleanup', async () => {
const ngZone = TestBed.inject(NgZone);
@@ -7764,7 +7751,6 @@ describe('platform-server full application hydration integration', () => {
class SimpleComponent {}
const envProviders = [
- provideZonelessChangeDetection(),
{provide: PlatformLocation, useClass: MockPlatformLocation},
provideRouter(routes),
] as unknown as Provider[];
diff --git a/packages/platform-server/test/incremental_hydration_spec.ts b/packages/platform-server/test/incremental_hydration_spec.ts
index 0f5392f29c6..1c7dd993743 100644
--- a/packages/platform-server/test/incremental_hydration_spec.ts
+++ b/packages/platform-server/test/incremental_hydration_spec.ts
@@ -10,25 +10,38 @@ import {
APP_ID,
ApplicationRef,
Component,
+ ɵDEHYDRATED_BLOCK_REGISTRY as DEHYDRATED_BLOCK_REGISTRY,
destroyPlatform,
+ ɵgetDocument as getDocument,
inject,
Input,
- NgZone,
+ ɵJSACTION_BLOCK_ELEMENT_MAP as JSACTION_BLOCK_ELEMENT_MAP,
+ ɵJSACTION_EVENT_CONTRACT as JSACTION_EVENT_CONTRACT,
+ PendingTasks,
PLATFORM_ID,
Provider,
QueryList,
+ ɵresetIncrementalHydrationEnabledWarnedForTests as resetIncrementalHydrationEnabledWarnedForTests,
signal,
+ ɵTimerScheduler as TimerScheduler,
ViewChildren,
ɵDEFER_BLOCK_DEPENDENCY_INTERCEPTOR,
- ɵDEHYDRATED_BLOCK_REGISTRY as DEHYDRATED_BLOCK_REGISTRY,
- ɵJSACTION_BLOCK_ELEMENT_MAP as JSACTION_BLOCK_ELEMENT_MAP,
- ɵJSACTION_EVENT_CONTRACT as JSACTION_EVENT_CONTRACT,
- ɵgetDocument as getDocument,
- ɵresetIncrementalHydrationEnabledWarnedForTests as resetIncrementalHydrationEnabledWarnedForTests,
- ɵTimerScheduler as TimerScheduler,
- provideZoneChangeDetection,
} from '@angular/core';
+import {
+ isPlatformServer,
+ Location,
+ ɵPLATFORM_BROWSER_ID as PLATFORM_BROWSER_ID,
+ PlatformLocation,
+} from '@angular/common';
+import {MockPlatformLocation} from '@angular/common/testing';
+import {TestBed} from '@angular/core/testing';
+import {
+ provideClientHydration,
+ withEventReplay,
+ withIncrementalHydration,
+} from '@angular/platform-browser';
+import {provideRouter, RouterLink, RouterOutlet, Routes} from '@angular/router';
import {getAppContents, prepareEnvironmentAndHydrate, resetTViewsFor} from './dom_utils';
import {
clearConsole,
@@ -41,20 +54,6 @@ import {
verifyNodeWasNotHydrated,
withDebugConsole,
} from './hydration_utils';
-import {
- isPlatformServer,
- Location,
- PlatformLocation,
- ɵPLATFORM_BROWSER_ID as PLATFORM_BROWSER_ID,
-} from '@angular/common';
-import {
- provideClientHydration,
- withEventReplay,
- withIncrementalHydration,
-} from '@angular/platform-browser';
-import {TestBed} from '@angular/core/testing';
-import {provideRouter, RouterLink, RouterOutlet, Routes} from '@angular/router';
-import {MockPlatformLocation} from '@angular/common/testing';
/**
* Emulates a dynamic import promise.
@@ -1410,7 +1409,6 @@ describe('platform-server partial hydration integration', () => {
): number => {
onIdleCallbackQueue.set(id, callback);
expect(idleCallbacksRequested).toBe(0);
- expect(NgZone.isInAngularZone()).toBe(true);
idleCallbacksRequested++;
return id++;
};
@@ -1469,10 +1467,7 @@ describe('platform-server partial hydration integration', () => {
}
const appId = 'custom-app-id';
- const providers = [
- {provide: APP_ID, useValue: appId},
- provideZoneChangeDetection() as any,
- ];
+ const providers = [{provide: APP_ID, useValue: appId}];
const hydrationFeatures = () => [withIncrementalHydration()];
const html = await ssr(SimpleComponent, {envProviders: providers, hydrationFeatures});
@@ -2062,10 +2057,18 @@ describe('platform-server partial hydration integration', () => {
this.value.set('end');
}
registry = inject(DEHYDRATED_BLOCK_REGISTRY);
+
+ constructor() {
+ // TODO: Understand why this is needed to get the full rendering of the HTML
+ // Without it, bindings aren't properly rendered in SSR and the test fails.
+ // There was no issue with the zone based scheduler.
+ const remove = inject(PendingTasks).add();
+ setTimeout(() => remove(), 10);
+ }
}
const appId = 'custom-app-id';
- const providers = [{provide: APP_ID, useValue: appId}, provideZoneChangeDetection() as any];
+ const providers = [{provide: APP_ID, useValue: appId}];
const hydrationFeatures = () => [withIncrementalHydration()];
const html = await ssr(SimpleComponent, {envProviders: providers, hydrationFeatures});
diff --git a/packages/platform-server/test/integration_spec.ts b/packages/platform-server/test/integration_spec.ts
index 9899e74dd50..a40f4fd9ff8 100644
--- a/packages/platform-server/test/integration_spec.ts
+++ b/packages/platform-server/test/integration_spec.ts
@@ -28,7 +28,6 @@ import {
destroyPlatform,
EnvironmentProviders,
getPlatform,
- HostListener,
Inject,
inject,
Injectable,
@@ -43,6 +42,7 @@ import {
provideNgReflectAttributes,
Provider,
provideZoneChangeDetection,
+ signal,
ɵSSR_CONTENT_INTEGRITY_MARKER as SSR_CONTENT_INTEGRITY_MARKER,
TransferState,
Type,
@@ -112,17 +112,17 @@ function createAppWithPendingTask(standalone: boolean) {
@Component({
standalone,
selector: 'app',
- template: `Completed: {{ completed }}`,
+ template: `Completed: {{ completed() }}`,
})
class PendingTasksApp {
- completed = 'No';
+ completed = signal('No');
constructor() {
const pendingTasks = coreInject(PendingTasks);
const removeTask = pendingTasks.add();
setTimeout(() => {
removeTask();
- this.completed = 'Yes';
+ this.completed.set('Yes');
});
}
}
@@ -138,7 +138,6 @@ const PendingTasksAppStandalone = createAppWithPendingTask(true);
exports: [PendingTasksApp],
imports: [ServerModule],
bootstrap: [PendingTasksApp],
- providers: [provideZoneChangeDetection()],
})
export class PendingTasksAppModule {}
@@ -309,23 +308,20 @@ class TitleAppModule {}
function createMyAsyncServerApp(standalone: boolean) {
@Component({
selector: 'app',
- template: '{{text}}',
+ template: '{{text()}}',
standalone,
})
class MyAsyncServerApp {
- text = '';
- h1 = '';
+ text = signal('');
+ h1 = signal('');
- @HostListener('window:scroll')
- track() {
- console.error('scroll');
- }
-
- ngOnInit() {
+ constructor() {
+ const remove = inject(PendingTasks).add();
Promise.resolve(null).then(() =>
setTimeout(() => {
- this.text = 'Works!';
- this.h1 = 'fine';
+ this.text.set('Works!');
+ this.h1.set('fine');
+ remove();
}, 10),
);
}
@@ -335,17 +331,19 @@ function createMyAsyncServerApp(standalone: boolean) {
}
const MyAsyncServerApp = createMyAsyncServerApp(false);
-const MyAsyncServerAppStandalone = getStandaloneBootstrapFn(createMyAsyncServerApp(true), [
- provideZoneChangeDetection(),
-]);
+const MyAsyncServerAppStandalone = getStandaloneBootstrapFn(createMyAsyncServerApp(true), []);
-@NgModule({
- declarations: [MyAsyncServerApp],
- imports: [BrowserModule, ServerModule],
- bootstrap: [MyAsyncServerApp],
- providers: [provideZoneChangeDetection()],
-})
-class AsyncServerModule {}
+function createAsyncServerModule(zoneless: boolean) {
+ @NgModule({
+ declarations: [MyAsyncServerApp],
+ imports: [BrowserModule, ServerModule],
+ bootstrap: [MyAsyncServerApp],
+ providers: zoneless ? [] : [provideZoneChangeDetection()],
+ })
+ class AsyncServerModule {}
+
+ return AsyncServerModule;
+}
function createSVGComponent(standalone: boolean) {
@Component({
@@ -643,6 +641,7 @@ const MyHiddenComponentStandalone = getStandaloneBootstrapFn(createMyHiddenCompo
})
class HiddenModule {}
+// TODO: Remove that IIFE, angular_jasmine_test only runs on nodes.
(function () {
if (getDOM().supportsDOMEvents) return; // NODE only
@@ -765,542 +764,570 @@ class HiddenModule {}
TestBed.resetTestingModule();
});
- it('should render with `createApplication`', async () => {
- const output = await renderApplication(
- async (context) => {
- const appRef = await createApplication(
- {
- providers: [provideZoneChangeDetection()],
- },
- context,
- );
- appRef.bootstrap(createMyAsyncServerApp(true));
- return appRef;
- },
- {document: doc},
- );
+ [true, false].forEach((zoneless: boolean) => {
+ it(`should render with \`createApplication \` (zoneless:${zoneless})`, async () => {
+ const output = await renderApplication(
+ async (context) => {
+ const appRef = await createApplication(
+ {
+ providers: [provideZoneChangeDetection()],
+ },
+ context,
+ );
+ appRef.bootstrap(createMyAsyncServerApp(true));
+ return appRef;
+ },
+ {document: doc},
+ );
- expect(output).toBe(expectedOutput);
- });
-
- it('using long form should work', async () => {
- const platform = platformServer([
- {
- provide: INITIAL_CONFIG,
- useValue: {document: doc},
- },
- ]);
-
- const moduleRef = await platform.bootstrapModule(AsyncServerModule);
- const applicationRef = moduleRef.injector.get(ApplicationRef);
- await applicationRef.whenStable();
- // Note: the `ng-server-context` is not present in this output, since
- // `renderModule` or `renderApplication` functions are not used here.
- const expectedOutput =
- '' +
- 'Works!fine
';
-
- expect(platform.injector.get(PlatformState).renderToString()).toBe(expectedOutput);
- });
-
- // Run the set of tests with regular and standalone components.
- [true, false].forEach((isStandalone: boolean) => {
- it(`using ${isStandalone ? 'renderApplication' : 'renderModule'} should work`, async () => {
- const options = {document: doc};
- const bootstrap = isStandalone
- ? renderApplication(MyAsyncServerAppStandalone, options)
- : renderModule(AsyncServerModule, options);
- const output = await bootstrap;
expect(output).toBe(expectedOutput);
});
- it(
- `using ${isStandalone ? 'renderApplication' : 'renderModule'} ` +
- `should allow passing a document reference`,
- async () => {
- const document = TestBed.inject(DOCUMENT);
-
- // Append root element based on the app selector.
- const rootEl = document.createElement('app');
- document.body.appendChild(rootEl);
-
- // Append a special marker to verify that we use a correct instance
- // of the document for rendering.
- const markerEl = document.createComment('test marker');
- document.body.appendChild(markerEl);
-
- const options = {document};
- const bootstrap = isStandalone
- ? renderApplication(MyAsyncServerAppStandalone, {document})
- : renderModule(AsyncServerModule, options);
- const output = await bootstrap.finally(() => {
- rootEl.remove();
- markerEl.remove();
- });
-
- expect(output).toBe(
- 'fakeTitle' +
- '' +
- 'Works!fine
' +
- '',
- );
- },
- );
-
- it(`works with SVG elements (standalone:${isStandalone})`, async () => {
- const options = {document: doc};
- const bootstrap = isStandalone
- ? renderApplication(SVGComponentStandalone, {...options})
- : renderModule(SVGServerModule, options);
- const output = await bootstrap;
- expect(output).toBe(
- '' +
- '',
- );
- });
-
- it('works with animation' + `(standalone:${isStandalone})`, async () => {
- const options = {document: doc};
- const bootstrap = isStandalone
- ? renderApplication(MyAnimationAppStandalone, options)
- : renderModule(AnimationServerModule, options);
- const output = await bootstrap;
- expect(output).toContain('Works!');
- expect(output).toContain('ng-trigger-myAnimation');
- expect(output).toContain('opacity: 1;');
- expect(output).toContain('transform: translate3d(0, 0, 0);');
- expect(output).toContain('font-weight: bold;');
- });
-
- it(
- 'should handle ViewEncapsulation.ShadowDom' + `(standalone:${isStandalone})`,
- async () => {
- const options = {document: doc};
- const bootstrap = isStandalone
- ? renderApplication(ShadowDomEncapsulationAppStandalone, options)
- : renderModule(ShadowDomExampleModule, options);
- const output = await bootstrap;
- expect(output).not.toBe('');
- expect(output).toContain('color: red');
- },
- );
-
- it(
- 'adds the `ng-server-context` attribute to host elements' +
- `(standalone:${isStandalone})`,
- async () => {
- const options = {
- document: doc,
- };
- const providers = [
- {
- provide: SERVER_CONTEXT,
- useValue: 'ssg',
- },
- ];
- const bootstrap = isStandalone
- ? renderApplication(MyStylesAppStandalone, {
- ...options,
- platformProviders: providers,
- })
- : renderModule(ExampleStylesModule, {
- ...options,
- extraProviders: providers,
- });
- const output = await bootstrap;
- expect(output).toMatch(
- //,
- );
- },
- );
-
- it('sanitizes the `serverContext` value' + `(standalone:${isStandalone})`, async () => {
- const options = {
- document: doc,
- };
- const providers = [
+ it(`using long form should work (zoneless:${zoneless})`, async () => {
+ const platform = platformServer([
{
- provide: SERVER_CONTEXT,
- useValue: '!!!Some extra chars&& -->