test(core): add e2e tests to ivy-trusted-types integration test (#39614)
Make sure that all Trusted Types-relevant sinks that can appear in an Angular template (e.g. not <script>, since it's forbidden) continue to work as expected with correct sanitization semantics, without introducing Trusted Types violations. PR Close #39614
This commit is contained in:
parent
c2298512b3
commit
569086a974
|
@ -1,5 +1,5 @@
|
|||
import { AppPage } from './app.po';
|
||||
import { browser, logging } from 'protractor';
|
||||
import {browser, logging} from 'protractor';
|
||||
import {AppPage} from './app.po';
|
||||
|
||||
describe('workspace-project App', () => {
|
||||
let page: AppPage;
|
||||
|
@ -13,7 +13,49 @@ describe('workspace-project App', () => {
|
|||
expect(await page.getTitleText()).toEqual('ivy-trusted-types app is running!');
|
||||
});
|
||||
|
||||
it('should sanitize and inject bound innerHTML', async () => {
|
||||
await page.navigateTo();
|
||||
expect(await page.getBoundHtmlText()).toEqual('Hello from bound HTML');
|
||||
expect(await page.boundHtmlIframeIsPresent()).toBe(false);
|
||||
});
|
||||
|
||||
it('should directly inject SafeHtml bound to innerHTML', async () => {
|
||||
await page.navigateTo();
|
||||
expect(await page.getBoundSafeHtmlText()).toEqual('Hello from bound SafeHtml');
|
||||
expect(await page.boundSafeHtmlIframeIsPresent()).toBe(true);
|
||||
});
|
||||
|
||||
it('should replace element with outerHTML contents', async () => {
|
||||
await page.navigateTo();
|
||||
expect(await page.getOuterHTMLText()).toBe('Hello from second outerHTML');
|
||||
});
|
||||
|
||||
it('should load iframe', async () => {
|
||||
await page.navigateTo();
|
||||
await browser.waitForAngularEnabled(false);
|
||||
await page.switchToIframe();
|
||||
expect(await page.getHeaderText()).toEqual('Hello from iframe');
|
||||
});
|
||||
|
||||
it('should load embed', async () => {
|
||||
await page.navigateTo();
|
||||
await browser.waitForAngularEnabled(false);
|
||||
await page.switchToEmbed();
|
||||
expect(await page.getHeaderText()).toEqual('Hello from embed');
|
||||
});
|
||||
|
||||
it('should load object', async () => {
|
||||
await page.navigateTo();
|
||||
await browser.waitForAngularEnabled(false);
|
||||
await page.switchToObject();
|
||||
expect(await page.getHeaderText()).toEqual('Hello from object');
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// Re-enable waiting for Angular in case we disabled it to navigate to a
|
||||
// non-Angular page
|
||||
await browser.waitForAngularEnabled(true);
|
||||
|
||||
// Assert that there are no errors emitted from the browser
|
||||
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
||||
expect(logs).not.toContain(jasmine.objectContaining({
|
||||
|
|
|
@ -5,7 +5,43 @@ export class AppPage {
|
|||
return browser.get(browser.baseUrl);
|
||||
}
|
||||
|
||||
async switchToIframe(): Promise<unknown> {
|
||||
return browser.switchTo().frame(await element(by.id('trusted-types-iframe')).getWebElement());
|
||||
}
|
||||
|
||||
async switchToObject(): Promise<unknown> {
|
||||
return browser.switchTo().frame(await element(by.id('trusted-types-object')).getWebElement());
|
||||
}
|
||||
|
||||
async switchToEmbed(): Promise<unknown> {
|
||||
return browser.switchTo().frame(await element(by.id('trusted-types-embed')).getWebElement());
|
||||
}
|
||||
|
||||
async getTitleText(): Promise<string> {
|
||||
return element(by.css('app-root .content span')).getText();
|
||||
}
|
||||
|
||||
async getBoundHtmlText(): Promise<string> {
|
||||
return element(by.css('#bound-html span')).getText();
|
||||
}
|
||||
|
||||
async getBoundSafeHtmlText(): Promise<string> {
|
||||
return element(by.css('#bound-safehtml span')).getText();
|
||||
}
|
||||
|
||||
async getOuterHTMLText(): Promise<string> {
|
||||
return element(by.id('outerhtml')).getText();
|
||||
}
|
||||
|
||||
async boundHtmlIframeIsPresent(): Promise<boolean> {
|
||||
return element(by.id('bound-html-iframe')).isPresent();
|
||||
}
|
||||
|
||||
async boundSafeHtmlIframeIsPresent(): Promise<boolean> {
|
||||
return element(by.id('bound-safehtml-iframe')).isPresent();
|
||||
}
|
||||
|
||||
async getHeaderText(): Promise<string> {
|
||||
return element(by.css('h1')).getText();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -530,5 +530,18 @@
|
|||
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
|
||||
|
||||
|
||||
<div id="trusted-types">
|
||||
<h1>Trusted Types tests</h1>
|
||||
|
||||
<div id="bound-html" [innerHTML]="html"></div>
|
||||
<div id="bound-safehtml" [innerHTML]="safeHtml"></div>
|
||||
<div id="outerhtml">
|
||||
<span [outerHTML]="replace">Hello from first outerHTML</span>
|
||||
</div>
|
||||
|
||||
<embed id="trusted-types-embed" src="data:text/html,<body><h1>Hello from embed</h1></body>" />
|
||||
<iframe id="trusted-types-iframe" [srcdoc]="iframeHtml"></iframe>
|
||||
<object id="trusted-types-object" [data]="safeResourceUrl" codebase="/"></object>
|
||||
</div>
|
||||
|
||||
<router-outlet></router-outlet>
|
|
@ -1,4 +1,5 @@
|
|||
import { Component } from '@angular/core';
|
||||
import {Component} from '@angular/core';
|
||||
import {DomSanitizer, SafeHtml, SafeResourceUrl} from '@angular/platform-browser';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
|
@ -7,4 +8,16 @@ import { Component } from '@angular/core';
|
|||
})
|
||||
export class AppComponent {
|
||||
title = 'ivy-trusted-types';
|
||||
html = `<span>Hello from bound HTML</span><iframe id="bound-html-iframe"></iframe>`;
|
||||
iframeHtml = `<h1>Hello from iframe</h1>`;
|
||||
replace = `<span>Hello from second outerHTML</span>`;
|
||||
safeHtml: SafeHtml;
|
||||
safeResourceUrl: SafeResourceUrl;
|
||||
|
||||
constructor(sanitizer: DomSanitizer) {
|
||||
this.safeHtml = sanitizer.bypassSecurityTrustHtml(
|
||||
`<span>Hello from bound SafeHtml</span><iframe id="bound-safehtml-iframe"></iframe>`);
|
||||
this.safeResourceUrl = sanitizer.bypassSecurityTrustResourceUrl(
|
||||
`data:text/html,<body><h1>Hello from object</h1></body>`);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue