Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/beta' into docs/component-doc-up…
Browse files Browse the repository at this point in the history
…dates
  • Loading branch information
joshuagraber committed Jun 7, 2024
1 parent 05a9a66 commit c7bbeaf
Show file tree
Hide file tree
Showing 21 changed files with 132 additions and 433 deletions.
88 changes: 64 additions & 24 deletions src/components/ErrorBoundary/PdapErrorBoundary.vue
Original file line number Diff line number Diff line change
@@ -1,25 +1,68 @@
<template>
<slot v-if="!error$" />
<component
:is="component"
v-if="error"
v-else
class="pdap-flex-container-center h-[full]"
:v-bind="params"
>
<h1>Oops, something went wrong!</h1>
<p class="max-w-full" data-test="error-boundary-message">
If you keep seeing this message, please email
<a href="mailto:[email protected]">[email protected]</a> for assistance.
</p>
</component>
<slot v-else />
</template>
<script>

<script setup lang="ts">
import { ComponentPublicInstance, onErrorCaptured, ref } from 'vue';
import { PdapErrorBoundaryProps, PdapErrorEmitted } from './types';
const props = withDefaults(defineProps<PdapErrorBoundaryProps>(), {
component: 'div',
onError: undefined,
params: undefined,
});
const emits = defineEmits<{
(event: 'onError', { error, vm, info }: PdapErrorEmitted): void;
}>();
const error$ = ref<Error>();
const info$ = ref<string | undefined>('');
function interceptError(
error: Error,
vm: ComponentPublicInstance | null,
info?: string
) {
error$.value = error;
info$.value = info;
props.onError?.(error, vm, info);
emits('onError', { error, vm, info });
}
/* Impossible and unwise to try testing this, so we remove from the coverage report */
/* c8 ignore next 3 */
onErrorCaptured((err, vm, info) => {
interceptError(err, vm, info);
});
</script>

<script lang="ts">
/**
* # `ErrorBoundary`
* Intercepts uncaught errors from its children and renders an error UI in place of its children.
*
* ## Props
* @prop {string} component Optional: the component to render as a fallback, defaults to 'div'
* @prop {PdapErrorBoundaryProps['onError']} onError Optional: callback to run on error, accepts two arguments, the error and the element (optional)
* @prop {Record<string, string>} params Optional: parameters to be forwarded to fallback
*
* ## Emits
* @emits onError includes object with `error`, and optionally `info` and `vm
*
* @example
* @example Top level
*
* <template>
* <AuthWrapper>
Expand All @@ -30,27 +73,24 @@
* <Footer :logo-image-src="acronym" />
* </AuthWrapper>
* </template>
*
* @example Within a component
<ErrorBoundary
class="col-span-full items-start"
component="div"
@on-error="({ error, vm, info }) => console.debug({ error, vm, info })"
>
<div class="col-span-full">
<p>
This is the content that will render inside the error boundary if
there is no error
</p>
<Button @click="triggerError">Click here to trigger error</Button>
</div>
</ErrorBoundary>
*
*/
export default {
props: {
component: {
type: String,
default: 'div',
},
},
data() {
return {
error: false,
};
},
/* TODO: figure out how to cover this lifecycle method in tests */
errorCaptured(error) {
this.interceptError(error);
},
methods: {
interceptError(error) {
this.error = error;
},
},
name: 'ErrorBoundary',
};
</script>
8 changes: 5 additions & 3 deletions src/components/ErrorBoundary/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
Intercepts uncaught errors from its children and renders an error UI in place of its children.

## Props
| name | required? | types | description | default |
| ----------- | --------- | -------- | ------------------------------- | ------- |
| `component` | no | `string` | component to render as fallback | `'div'` |
| name | required? | types | description | default |
| ----------- | --------- | ------------------------------------------------------------------------------- | ------------------------------- | ----------- |
| `component` | no | `string` | component to render as fallback | `'div'` |
| `onError` | no | `(error: Error, target?: ComponentPublicInstance \| null \| undefined) => void` | callback to run on error | `undefined` |
| `params` | no | `Record<string,string>` | params to forward to fallback | `undefined` |

## Example
_From data-sources `App.vue`: This will catch any uncaught error at the route level and render the error fallback_
Expand Down
21 changes: 20 additions & 1 deletion src/components/ErrorBoundary/error-boundary.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils';
import { beforeEach, describe, expect, it } from 'vitest';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import ErrorBoundary from './PdapErrorBoundary.vue';
import { nextTick } from 'vue';

Expand Down Expand Up @@ -28,4 +28,23 @@ describe('ErrorBoundary', () => {
);
expect(wrapper.html()).toMatchSnapshot();
});

it('calls the onError callback when an error occurs', async () => {
const onErrorSpy = vi.fn();

wrapper = mount(ErrorBoundary, {
props: {
onError: onErrorSpy,
},
slots: {
default: '<div>Default Content</div>',
},
});

const testError = new Error('Test Error');
wrapper.vm.interceptError(testError);
await nextTick();

expect(onErrorSpy).toHaveBeenCalledWith(testError, undefined, undefined);
});
});
1 change: 1 addition & 0 deletions src/components/ErrorBoundary/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as ErrorBoundary } from './PdapErrorBoundary.vue';
17 changes: 17 additions & 0 deletions src/components/ErrorBoundary/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ComponentPublicInstance } from 'vue';

export interface PdapErrorEmitted {
error: Error;
vm: ComponentPublicInstance | null;
info?: string;
}

export interface PdapErrorBoundaryProps {
component: string;
onError?: (
error: Error,
target?: ComponentPublicInstance | null | undefined,
info?: string
) => void;
params?: Record<string, string>;
}
64 changes: 0 additions & 64 deletions src/components/FlexContainer/FlexContainer.vue

This file was deleted.

This file was deleted.

37 changes: 0 additions & 37 deletions src/components/FlexContainer/flex-container.spec.ts

This file was deleted.

3 changes: 0 additions & 3 deletions src/components/FlexContainer/index.ts

This file was deleted.

4 changes: 0 additions & 4 deletions src/components/FlexContainer/types.ts

This file was deleted.

66 changes: 0 additions & 66 deletions src/components/GridContainer/GridContainer.vue

This file was deleted.

9 changes: 0 additions & 9 deletions src/components/GridContainer/__snapshots__/grid.spec.ts.snap

This file was deleted.

Loading

0 comments on commit c7bbeaf

Please sign in to comment.