-
Notifications
You must be signed in to change notification settings - Fork 25.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(platform-server): call
onSerialize
when state is empty (#47888)
Commit a0b2d36#diff-3975e0ee5aa3e06ecbcd76f5fa5134612f7fd2e6802ca7d370973bd410aab55cR25-R31 changed the serialization phase logic so that when the state is empty the script tag is not added to the document. As a side effect, this caused the `toJson` not called which caused the `onSerialize` callbacks also not to be called. These callbacks are used to provide the value for a key when `toJson` is called. Example: ngrx/platform#101 (comment) Closes #47172 PR Close #47888
- Loading branch information
1 parent
8707475
commit d2d9bbf
Showing
4 changed files
with
96 additions
and
104 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
/** | ||
* @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, NgModule,} from '@angular/core'; | ||
import {BrowserModule, makeStateKey, TransferState} from '@angular/platform-browser'; | ||
import {renderModule, ServerModule} from '@angular/platform-server'; | ||
|
||
describe('transfer_state', () => { | ||
const defaultExpectedOutput = | ||
'<html><head></head><body><app ng-version="0.0.0-PLACEHOLDER" ng-server-context="other">Works!</app><script id="transfer-state" type="application/json">{&q;test&q;:10}</script></body></html>'; | ||
|
||
it('adds transfer script tag when using renderModule', async () => { | ||
const STATE_KEY = makeStateKey<number>('test'); | ||
|
||
@Component({selector: 'app', template: 'Works!'}) | ||
class TransferComponent { | ||
constructor(private transferStore: TransferState) { | ||
this.transferStore.set(STATE_KEY, 10); | ||
} | ||
} | ||
|
||
@NgModule({ | ||
bootstrap: [TransferComponent], | ||
declarations: [TransferComponent], | ||
imports: [BrowserModule.withServerTransition({appId: 'transfer'}), ServerModule], | ||
}) | ||
class TransferStoreModule { | ||
} | ||
|
||
const output = await renderModule(TransferStoreModule, {document: '<app></app>'}); | ||
expect(output).toBe(defaultExpectedOutput); | ||
}); | ||
|
||
it('cannot break out of <script> tag in serialized output', async () => { | ||
const STATE_KEY = makeStateKey<string>('testString'); | ||
|
||
@Component({selector: 'esc-app', template: 'Works!'}) | ||
class EscapedComponent { | ||
constructor(private transferStore: TransferState) { | ||
this.transferStore.set(STATE_KEY, '</script><script>alert(\'Hello&\' + "World");'); | ||
} | ||
} | ||
@NgModule({ | ||
bootstrap: [EscapedComponent], | ||
declarations: [EscapedComponent], | ||
imports: [BrowserModule.withServerTransition({appId: 'transfer'}), ServerModule], | ||
}) | ||
class EscapedTransferStoreModule { | ||
} | ||
|
||
const output = | ||
await renderModule(EscapedTransferStoreModule, {document: '<esc-app></esc-app>'}); | ||
expect(output).toBe( | ||
'<html><head></head><body><esc-app ng-version="0.0.0-PLACEHOLDER" ng-server-context="other">Works!</esc-app>' + | ||
'<script id="transfer-state" type="application/json">' + | ||
'{&q;testString&q;:&q;&l;/script&g;&l;script&g;' + | ||
'alert(&s;Hello&a;&s; + \\&q;World\\&q;);&q;}</script></body></html>'); | ||
}); | ||
|
||
it('adds transfer script tag when setting state during onSerialize', async () => { | ||
const STATE_KEY = makeStateKey<number>('test'); | ||
|
||
@Component({selector: 'app', template: 'Works!'}) | ||
class TransferComponent { | ||
constructor(private transferStore: TransferState) { | ||
this.transferStore.onSerialize(STATE_KEY, () => 10); | ||
} | ||
} | ||
|
||
@NgModule({ | ||
bootstrap: [TransferComponent], | ||
declarations: [TransferComponent], | ||
imports: [BrowserModule.withServerTransition({appId: 'transfer'}), ServerModule], | ||
}) | ||
class TransferStoreModule { | ||
} | ||
|
||
const output = await renderModule(TransferStoreModule, {document: '<app></app>'}); | ||
expect(output).toBe(defaultExpectedOutput); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters