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:
Bjarki 2020-11-09 18:36:16 +00:00 committed by Andrew Kushnir
parent c2298512b3
commit 569086a974
4 changed files with 108 additions and 4 deletions

View File

@ -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({

View File

@ -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();
}
}

View File

@ -530,5 +530,18 @@
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<div id="trusted-types">
<h1>Trusted Types tests</h1>
<router-outlet></router-outlet>
<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,&lt;body&gt;&lt;h1&gt;Hello from embed&lt;/h1&gt;&lt;/body&gt;" />
<iframe id="trusted-types-iframe" [srcdoc]="iframeHtml"></iframe>
<object id="trusted-types-object" [data]="safeResourceUrl" codebase="/"></object>
</div>
<router-outlet></router-outlet>

View File

@ -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>`);
}
}