Skip to content

Commit f470332

Browse files
committed
Add CSP trusted types tests.
1 parent 19f57a3 commit f470332

File tree

2 files changed

+118
-0
lines changed

2 files changed

+118
-0
lines changed

src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ export function setCSPTrustedTypesPolicy(policy: CSPTrustedTypesPolicy | Promise
1818
cspTrustedTypesPolicyPromise = policy === null ? policy : Promise.resolve(policy)
1919
}
2020

21+
// TODO: find another way to make this available for testing.
22+
;(globalThis as any).setCSPTrustedTypesPolicy = setCSPTrustedTypesPolicy
23+
2124
export default class IncludeFragmentElement extends HTMLElement {
2225
static get observedAttributes(): string[] {
2326
return ['src', 'loading']

test/test.js

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ const responses = {
3131
}
3232
})
3333
},
34+
'/x-server-sanitized': function () {
35+
return new Response('This response should be marked as sanitized using a custom header!', {
36+
status: 200,
37+
headers: {
38+
'Content-Type': 'text/html; charset=utf-8',
39+
'X-Server-Sanitized': 'sanitized=true'
40+
}
41+
})
42+
},
3443
'/boom': function () {
3544
return new Response('boom', {
3645
status: 500
@@ -607,4 +616,110 @@ suite('include-fragment-element', function () {
607616
assert.equal(document.querySelector('#replaced').textContent, 'hello')
608617
})
609618
})
619+
620+
suite('CSP trusted types', () => {
621+
teardown(() => {
622+
setCSPTrustedTypesPolicy(null)
623+
})
624+
625+
test('can set a pass-through mock CSP trusted types policy', async function () {
626+
let policyCalled = false
627+
setCSPTrustedTypesPolicy({
628+
createHTML: htmlText => {
629+
policyCalled = true
630+
return htmlText
631+
}
632+
})
633+
634+
const el = document.createElement('include-fragment')
635+
el.src = '/hello'
636+
637+
const data = await el.data
638+
assert.equal('<div id="replaced">hello</div>', data)
639+
assert.ok(policyCalled)
640+
})
641+
642+
test('can set and clear a mutating mock CSP trusted types policy', async function () {
643+
let policyCalled = false
644+
setCSPTrustedTypesPolicy({
645+
createHTML: htmlText => {
646+
policyCalled = true
647+
return '<b>replacement</b>'
648+
}
649+
})
650+
651+
const el = document.createElement('include-fragment')
652+
el.src = '/hello'
653+
const data = await el.data
654+
assert.equal('<b>replacement</b>', data)
655+
assert.ok(policyCalled)
656+
657+
setCSPTrustedTypesPolicy(null)
658+
const el2 = document.createElement('include-fragment')
659+
el2.src = '/hello'
660+
const data2 = await el2.data
661+
assert.equal('<div id="replaced">hello</div>', data2)
662+
})
663+
664+
test('can set a real CSP trusted types policy in Chromium', async function () {
665+
let policyCalled = false
666+
const policy = globalThis.trustedTypes.createPolicy('test1', {
667+
createHTML: htmlText => {
668+
policyCalled = true
669+
return htmlText
670+
}
671+
})
672+
setCSPTrustedTypesPolicy(policy)
673+
674+
const el = document.createElement('include-fragment')
675+
el.src = '/hello'
676+
const data = await el.data
677+
assert.equal('<div id="replaced">hello</div>', data)
678+
assert.ok(policyCalled)
679+
})
680+
681+
test('can reject data using a mock CSP trusted types policy', async function () {
682+
setCSPTrustedTypesPolicy({
683+
createHTML: htmlText => {
684+
throw new Error('Rejected data!')
685+
}
686+
})
687+
688+
const el = document.createElement('include-fragment')
689+
el.src = '/hello'
690+
try {
691+
await el.data
692+
assert.ok(false)
693+
} catch (error) {
694+
assert.match(error, /Rejected data!/)
695+
}
696+
})
697+
698+
test('can access headers using a mock CSP trusted types policy', async function () {
699+
setCSPTrustedTypesPolicy({
700+
createHTML: (htmlText, response) => {
701+
if (response.headers.get("X-Server-Sanitized") !== "sanitized=true") {
702+
// Note: this will reject the contents, but the error may be caught before it shows in the JS console.
703+
throw new Error("Rejecting HTML that was not marked by the server as sanitized.");
704+
}
705+
return htmlText;
706+
}
707+
})
708+
709+
const el = document.createElement('include-fragment')
710+
el.src = '/hello'
711+
try {
712+
await el.data
713+
assert.ok(false)
714+
} catch (error) {
715+
assert.match(error, /Rejecting HTML that was not marked by the server as sanitized./)
716+
}
717+
718+
const el2 = document.createElement('include-fragment')
719+
el2.src = '/x-server-sanitized'
720+
721+
const data2 = await el2.data
722+
assert.equal('This response should be marked as sanitized using a custom header!', data2)
723+
})
724+
})
610725
})

0 commit comments

Comments
 (0)