Here's a better and tested safe pipe:
import { Pipe, PipeTransform, SecurityContext } from '@angular/core';
import {
DomSanitizer,
SafeHtml,
SafeResourceUrl,
SafeScript,
SafeStyle,
SafeUrl,
SafeValue,
} from '@angular/platform-browser';
@Pipe({
name: 'safe',
})
export class SafePipe implements PipeTransform {
constructor(private readonly domSanitizer: DomSanitizer) {}
transform(
value: string | undefined,
type: string,
bypass: boolean
):
| SafeHtml
| SafeStyle
| SafeScript
| SafeUrl
| SafeResourceUrl
| SafeValue
| null {
if (!value) {
return null;
}
switch (type) {
case 'style':
return bypass
? this.domSanitizer.bypassSecurityTrustStyle(value)
: this.domSanitizer.sanitize(SecurityContext.STYLE, value);
case 'script':
return bypass
? this.domSanitizer.bypassSecurityTrustScript(value)
: this.domSanitizer.sanitize(SecurityContext.SCRIPT, value);
case 'url':
return bypass
? this.domSanitizer.bypassSecurityTrustUrl(value)
: this.domSanitizer.sanitize(SecurityContext.URL, value);
case 'resourceUrl':
return bypass
? this.domSanitizer.bypassSecurityTrustResourceUrl(value)
: this.domSanitizer.sanitize(SecurityContext.RESOURCE_URL, value);
default:
return bypass
? this.domSanitizer.bypassSecurityTrustHtml(value)
: this.domSanitizer.sanitize(SecurityContext.HTML, value);
}
}
}
import { DomSanitizer } from '@angular/platform-browser';
import { SafePipe } from './safe.pipe';
const mockDomSanitizer = ({
sanitize: jest.fn(),
bypassSecurityTrustHtml: jest.fn(),
bypassSecurityTrustStyle: jest.fn(),
bypassSecurityTrustUrl: jest.fn(),
bypassSecurityTrustResourceUrl: jest.fn(),
bypassSecurityTrustScript: jest.fn(),
} as unknown) as DomSanitizer;
describe('SafePipe', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should return null value when value received is undefined', () => {
const pipe = new SafePipe(mockDomSanitizer);
expect(pipe.transform(undefined, 'style', true)).toBeNull();
});
test.each([
{ a: 'style', b: true, expected: 'bypassSecurityTrustStyle' },
{ a: 'script', b: true, expected: 'bypassSecurityTrustScript' },
{ a: 'url', b: true, expected: 'bypassSecurityTrustUrl' },
{ a: 'resourceUrl', b: true, expected: 'bypassSecurityTrustResourceUrl' },
{ a: 'html', b: true, expected: 'bypassSecurityTrustHtml' },
])('should call the correspondent method', ({ a, b, expected }) => {
const pipe = new SafePipe(mockDomSanitizer);
pipe.transform('value', a, b);
const domSanitizer = mockDomSanitizer as never;
expect(domSanitizer[expected]).toHaveBeenCalled();
});
test.each([
{ a: 'style', b: false, expected: 'sanitize' },
{ a: 'script', b: false, expected: 'sanitize' },
{ a: 'url', b: false, expected: 'sanitize' },
{ a: 'resourceUrl', b: false, expected: 'sanitize' },
{ a: 'html', b: false, expected: 'sanitize' },
])('should call the correspondent method', ({ a, b, expected }) => {
const pipe = new SafePipe(mockDomSanitizer);
pipe.transform('value', a, b);
const domSanitizer = mockDomSanitizer as never;
expect(domSanitizer[expected]).toHaveBeenCalled();
});
});