mirror of
https://github.com/cypress-io/cypress.git
synced 2026-05-05 06:20:44 -05:00
92eac2f67e
* refactor: reworking client-side error shape * feat: add the CodeFrame to baseerror * consolidate baseError handling, type fixes * Fix UNIFY-1164 w/ test cleanup to avoid intercepting * fix types, cleanup based on review / Brian * fix: imports / types / tests * cleanup tests, fix TSError location, add reinitializeCypress mutation * fix: show correct stack trace file name (#20410) * Improve comments for regexes / TSError capture * feat: Add codeframe to error, address PR comments * update snapshot * change codeframe impl, per Brian's request * Attempt to fix test flake Co-authored-by: ElevateBart <ledouxb@gmail.com> Co-authored-by: Alejandro Estrada <estrada9166@hotmail.com>
137 lines
4.1 KiB
Vue
137 lines
4.1 KiB
Vue
<template>
|
|
<div
|
|
v-if="baseError"
|
|
class="mx-auto space-y-32px text-center min-w-476px max-w-848px pt-16px children:text-center"
|
|
>
|
|
<div>
|
|
<h1
|
|
v-if="baseError.title"
|
|
class="font-medium leading-snug pb-24px text-32px text-gray-900"
|
|
data-testid="error-header"
|
|
>
|
|
<slot name="header">
|
|
{{ baseError.title }}
|
|
</slot>
|
|
</h1>
|
|
<!-- eslint-disable vue/multiline-html-element-content-newline -->
|
|
|
|
<slot name="message">
|
|
<Alert
|
|
:title="baseError.errorName"
|
|
status="error"
|
|
body-class="px-0px bg-red-50"
|
|
alert-class="bg-red-50"
|
|
header-class="bg-red-100 text-red-600 rounded-b-none"
|
|
:icon="ErrorOutlineIcon"
|
|
icon-classes="icon-dark-red-400"
|
|
max-height="none"
|
|
>
|
|
<div class="border-b-1 border-b-red-100 p-16px pt-0">
|
|
<div
|
|
ref="markdownTarget"
|
|
class="text-red-500"
|
|
data-testid="error-message"
|
|
v-html="markdown"
|
|
/>
|
|
<ErrorCodeFrame
|
|
v-if="baseError.codeFrame"
|
|
:gql="baseError.codeFrame"
|
|
/>
|
|
</div>
|
|
<div
|
|
class="m-16px mb-0 overflow-hidden"
|
|
>
|
|
<Collapsible
|
|
disable
|
|
max-height="none"
|
|
:initially-open="baseError.isUserCodeError"
|
|
>
|
|
<template #target="{open, toggle}">
|
|
<p
|
|
class="gap-8px inline-flex items-center justify-center"
|
|
:class="{'pb-8px': open}"
|
|
:data-cy="`stack-open-${open}`"
|
|
>
|
|
<i-cy-chevron-right-small_x16
|
|
class="min-w-8px min-h-8px transform duration-150 icon-dark-red-400"
|
|
:class="{'rotate-90': open}"
|
|
/>
|
|
<a
|
|
href="#"
|
|
class="cursor-pointer font-medium outline-none text-red-600 hocus:underline"
|
|
@click="toggle()"
|
|
@keypress.space.enter.self.prevent="toggle()"
|
|
>{{ t('launchpadErrors.generic.stackTraceLabel') }}</a>
|
|
</p>
|
|
</template>
|
|
<pre
|
|
data-testid="error-header"
|
|
class="bg-white rounded font-light border-1 border-red-200 p-16px overflow-auto"
|
|
v-html="baseError.errorStack"
|
|
/>
|
|
</Collapsible>
|
|
</div>
|
|
</Alert>
|
|
</slot>
|
|
<!-- eslint-enable vue/multiline-html-element-content-newline -->
|
|
|
|
<slot name="stack" />
|
|
</div>
|
|
<div class="w-full gap-16px inline-flex">
|
|
<slot name="footer">
|
|
<Button
|
|
v-if="props.retry"
|
|
size="lg"
|
|
variant="primary"
|
|
data-testid="error-retry-button"
|
|
:prefix-icon="RestartIcon"
|
|
prefix-icon-class="icon-dark-white"
|
|
@click="retry"
|
|
>
|
|
{{ t('launchpadErrors.generic.retryButton') }}
|
|
</Button>
|
|
</slot>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { ref, computed } from 'vue'
|
|
import { gql } from '@urql/vue'
|
|
import Button from '@cy/components/Button.vue'
|
|
import { useI18n } from '@cy/i18n'
|
|
import type { BaseErrorFragment } from '../generated/graphql'
|
|
import Alert from '@cy/components/Alert.vue'
|
|
import Collapsible from '@cy/components/Collapsible.vue'
|
|
import { useMarkdown } from '@packages/frontend-shared/src/composables/useMarkdown'
|
|
import RestartIcon from '~icons/cy/restart_x16.svg'
|
|
import ErrorOutlineIcon from '~icons/cy/status-errored-outline_x16.svg'
|
|
import ErrorCodeFrame from './ErrorCodeFrame.vue'
|
|
|
|
gql`
|
|
fragment BaseError on ErrorWrapper {
|
|
title
|
|
errorName
|
|
errorStack
|
|
errorType
|
|
errorMessage
|
|
isUserCodeError
|
|
codeFrame {
|
|
...ErrorCodeFrame
|
|
}
|
|
}
|
|
`
|
|
|
|
const { t } = useI18n()
|
|
|
|
const props = defineProps<{
|
|
gql: BaseErrorFragment
|
|
retry?: () => void
|
|
onReadDocs?: () => void
|
|
}>()
|
|
|
|
const markdownTarget = ref()
|
|
const baseError = computed(() => props.gql)
|
|
const { markdown } = useMarkdown(markdownTarget, computed(() => props.gql.errorMessage), { classes: { code: ['bg-error-200'] } })
|
|
</script>
|