Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improved Alpine error resiliency and logging (#2027)
* Iteration on error logging, adding event on errors for plugins to listen to. * Iteration on error logging, adding event on errors for plugins to listen to. ( pulled package-lock.json ) * Iteration on error logging, adding event on errors for plugins to listen to. -> fixed import from csp * move el and expression onto detail object directly * add back error for better dev experience * fix two bad tests that fail when exception handling is working * remove test since empty x-init is not valid * remove error event dispatching * remove unnecessary try/catch that should be handled internally * Fixed extra tab * Removed unused import * prevent useless 'func is not a function' errors Co-authored-by: jacobp <mozillafirefox1> Co-authored-by: dand <daniel.dent@borderconnect.com>
- Loading branch information
1 parent
52ff275
commit c5ffa11
Showing
8 changed files
with
272 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
export function tryCatch(el, expression, callback, ...args) { | ||
try { | ||
return callback(...args) | ||
} catch (e) { | ||
handleError( e, el, expression ) | ||
} | ||
} | ||
|
||
export function handleError(error, el, expression = undefined) { | ||
Object.assign( error, { el, expression } ) | ||
|
||
console.warn(`Alpine Expression Error: ${error.message}\n\n${ expression ? 'Expression: \"' + expression + '\"\n\n' : '' }`, el) | ||
|
||
setTimeout( () => { throw error }, 0 ) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
import { haveText, html, test } from '../utils' | ||
|
||
export function setupConsoleInterceptor( ...targetIds ) { | ||
const mappedTargetIds = targetIds.map( tid => `'${tid}'` ).join( ',' ) | ||
return ` | ||
let errorContainer = document.createElement('div'); | ||
errorContainer.id = 'errors' | ||
errorContainer.textContent = 'false' | ||
document.querySelector('#root').after(errorContainer) | ||
console.warnlog = console.warn.bind(console) | ||
console.warn = function () { | ||
document.getElementById( 'errors' ).textContent = [${mappedTargetIds}].some( target => arguments[1] === document.getElementById( target ) ) | ||
console.warnlog.apply(console, arguments) | ||
} | ||
` | ||
} | ||
|
||
export function assertConsoleInterceptorHadErrorWithCorrectElement() { | ||
return ({get}) => { | ||
get('#errors').should(haveText('true')) | ||
}; | ||
} | ||
|
||
test('x-for identifier issue', | ||
[html` | ||
<div x-data="{ items: ['foo'] }"> | ||
<template id="xfor" x-for="item in itemzzzz"> | ||
<span x-text="item"></span> | ||
</template> | ||
</div> | ||
`, | ||
setupConsoleInterceptor( "xfor" ) | ||
], | ||
assertConsoleInterceptorHadErrorWithCorrectElement(), | ||
true | ||
) | ||
|
||
test('x-text identifier issue', | ||
[html` | ||
<div x-data="{ items: ['foo'] }"> | ||
<template x-for="item in items"> | ||
<span id="xtext" x-text="itemzzz"></span> | ||
</template> | ||
</div> | ||
`, | ||
setupConsoleInterceptor( "xtext" ) | ||
], | ||
assertConsoleInterceptorHadErrorWithCorrectElement(), | ||
true | ||
) | ||
|
||
test('x-init identifier issue', | ||
[html` | ||
<div id="xinit" x-data x-init="doesNotExist()"> | ||
</div> | ||
`, | ||
setupConsoleInterceptor( "xinit" ) | ||
], | ||
assertConsoleInterceptorHadErrorWithCorrectElement(), | ||
true | ||
) | ||
|
||
test('x-show identifier issue', | ||
[html` | ||
<div id="xshow" x-data="{isOpen: true}" x-show="isVisible"> | ||
</div> | ||
`, | ||
setupConsoleInterceptor( "xshow" ) | ||
], | ||
assertConsoleInterceptorHadErrorWithCorrectElement(), | ||
true | ||
) | ||
|
||
test('x-bind class object syntax identifier issue', | ||
[html` | ||
<div x-data="{isOpen: true}"> | ||
<div id="xbind" :class="{ 'block' : isVisible, 'hidden' : !isVisible }"></div> | ||
</div> | ||
`, | ||
setupConsoleInterceptor( "xbind" ) | ||
], | ||
assertConsoleInterceptorHadErrorWithCorrectElement(), | ||
true | ||
) | ||
|
||
test('x-model identifier issue', | ||
[html` | ||
<div x-data="{value: ''}"> | ||
<input id="xmodel" x-model="thething"/> | ||
</div> | ||
`, | ||
setupConsoleInterceptor( "xmodel" ) | ||
], | ||
assertConsoleInterceptorHadErrorWithCorrectElement(), | ||
true | ||
) | ||
|
||
test('x-if identifier issue', | ||
[html` | ||
<div x-data="{value: ''}"> | ||
<template id="xif" x-if="valuez === ''"> | ||
<span>Words</span> | ||
</template> | ||
</div> | ||
`, | ||
setupConsoleInterceptor( "xif" ) | ||
], | ||
assertConsoleInterceptorHadErrorWithCorrectElement(), | ||
true | ||
) | ||
|
||
test('x-if identifier issue ( function )', | ||
[html` | ||
<div x-data="{shouldOpen: function(){}}"> | ||
<template id="xif" x-if="isOpen()"> | ||
<span>Words</span> | ||
</template> | ||
</div> | ||
`, | ||
setupConsoleInterceptor( "xif" ) | ||
], | ||
assertConsoleInterceptorHadErrorWithCorrectElement(), | ||
true | ||
) | ||
|
||
test('x-effect identifier issue', | ||
[html` | ||
<div id="xeffect" x-data="{ label: 'Hello' }" x-effect="System.out.println(label)"> | ||
</div> | ||
`, | ||
setupConsoleInterceptor( "xeffect" ) | ||
], | ||
assertConsoleInterceptorHadErrorWithCorrectElement(), | ||
true | ||
) | ||
|
||
test('x-on identifier issue', | ||
[html` | ||
<div x-data="{ label: 'Hello' }"> | ||
<div x-text="label"></div> | ||
<button id="xon" x-on:click="labelz += ' World!'">Change Message</button> | ||
</div> | ||
`, | ||
setupConsoleInterceptor( "xon" ) | ||
], | ||
({ get }) => { | ||
get( "#xon" ).click() | ||
get( "#errors" ).should(haveText('true')) | ||
}, | ||
true | ||
) | ||
|
||
test('x-data syntax error', | ||
[html` | ||
<div id="xdata" x-data="{ label: 'Hello' }aaa"> | ||
</div> | ||
`, | ||
setupConsoleInterceptor( "xdata" ) | ||
], | ||
assertConsoleInterceptorHadErrorWithCorrectElement(), | ||
true | ||
) | ||
|
||
test('if statement syntax error', | ||
[html` | ||
<div x-data="{ label: 'Hello' }"> | ||
<div id="xtext" x-text="if( false { label } else { 'bye' }"></div> | ||
</div> | ||
`, | ||
setupConsoleInterceptor( "xtext" ) | ||
], | ||
assertConsoleInterceptorHadErrorWithCorrectElement(), | ||
true | ||
) | ||
|
||
test('x-data with reference error and multiple errors', | ||
[html` | ||
<div id="xdata" x-data="{ items : [ {v:'one'},{v:'two'}], replaceItems }"> | ||
<template id="xtext" x-for="item in items"> | ||
<span x-text="item.v"></span> | ||
</template> | ||
</div> | ||
`, | ||
setupConsoleInterceptor( "xdata", "xtext" ) | ||
], | ||
assertConsoleInterceptorHadErrorWithCorrectElement(), | ||
true | ||
) | ||
|
||
test('evaluation with syntax error', | ||
[html` | ||
<div x-data="{value: ''}"> | ||
<template id="xif" x-if="value ==== ''"> | ||
<span>Words</span> | ||
</template> | ||
</div> | ||
`, | ||
setupConsoleInterceptor( "xif" ) | ||
], | ||
assertConsoleInterceptorHadErrorWithCorrectElement(), | ||
true | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.