feat: render throws on unknown elements

BREAKING CHANGE: `render` will throw if any custom elements (tag name
containing `-`) are found not registered in the injector.

This helps avoid the scenario where a child component/directive under
test isn't getting tested.

The behavior can be disabled via the `ignoreUnknownElements` option.
ts
Jason Staten 5 years ago
parent 14271ad0fc
commit 9ea5d678df

@ -41,3 +41,30 @@ test('assigns to scope', () => {
'Unable to find an element with the text: Hello World.',
)
})
test('throws on unknown custom elements', () => {
angular.module('atl').component('atlParent', {
template: `
<h1>Hi</hz>
<atl-child></atl-child>
`,
})
expect(() => render(`<atl-parent></atl-parent>`)).toThrow(
'Unknown component/directive "ATL-CHILD"',
)
})
test('suppresses unknown custom elements error', () => {
angular.module('atl').component('atlParent', {
template: `
<h1>Hi</hz>
<atl-child></atl-child>
`,
})
const {container} = render(`<atl-parent></atl-parent>`, {
ignoreUnknownElements: true,
})
expect(container.querySelector('atl-child')).toBeDefined()
})

@ -10,7 +10,16 @@ import {
const mountedContainers = new Set()
const mountedScopes = new Set()
function render(ui, {container, baseElement = container, queries, scope} = {}) {
function render(
ui,
{
container,
baseElement = container,
queries,
scope,
ignoreUnknownElements,
} = {},
) {
if (!baseElement) {
// default to document.body instead of documentElement to avoid output of potentially-large
// head elements (such as JSS style blocks) in debug output
@ -37,6 +46,10 @@ function render(ui, {container, baseElement = container, queries, scope} = {}) {
$scope.$digest()
if (!ignoreUnknownElements) {
assertNoUnknownElements(container)
}
return {
container,
baseElement,
@ -85,6 +98,26 @@ function cleanupScope(scope) {
mountedScopes.delete(scope)
}
function toCamel(s) {
return s
.toLowerCase()
.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase())
}
function assertNoUnknownElements(element) {
const {tagName} = element
if (tagName.includes('-')) {
const $injector = getAngularService('$injector')
const directiveName = `${toCamel(tagName)}Directive`
if (!$injector.has(directiveName)) {
throw Error(
`Unknown component/directive "${tagName}". Are you missing an import?`,
)
}
}
Array.from(element.children).forEach(assertNoUnknownElements)
}
function getAngularService(name) {
let service
angular.mock.inject([

Loading…
Cancel
Save