Commit e1e8b15d authored by Laura Montemayor's avatar Laura Montemayor Committed by Clement Ho

Updates parent component and adds js-div

* Adds initialization function for sentry stack trace
* Adds div to project/issues/show to display component
* Updates parent component with actions and getter
parent e1d75f5c
......@@ -4,11 +4,13 @@ import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
import ZenMode from '~/zen_mode';
import '~/notes/index';
import initIssueableApp from '~/issue_show';
import initSentryErrorStackTraceApp from '~/sentry_error_stack_trace';
import initRelatedMergeRequestsApp from '~/related_merge_requests';
import initVueIssuableSidebarApp from '~/issuable_sidebar/sidebar_bundle';
export default function() {
initIssueableApp();
initSentryErrorStackTraceApp();
initRelatedMergeRequestsApp();
new Issue(); // eslint-disable-line no-new
new ShortcutsIssuable(); // eslint-disable-line no-new
......
<script>
import Stacktrace from '~/error_tracking/components/stacktrace.vue';
import { GlLoadingIcon } from '@gitlab/ui';
import { mapActions, mapState, mapGetters } from 'vuex';
export default {
name: 'SentryErrorStackTrace',
components: {
Stacktrace,
GlLoadingIcon,
},
props: {
issueStackTracePath: {
type: String,
required: true,
},
},
computed: {
...mapState('details', ['loadingStacktrace', 'stacktraceData']),
...mapGetters('details', ['stacktrace']),
},
mounted() {
this.startPollingStacktrace(this.issueStackTracePath);
},
methods: {
...mapActions('details', ['startPollingStacktrace']),
},
};
</script>
<template>
<div>
<div :class="{ 'border-bottom-0': loadingStacktrace }" class="card card-slim mt-4 mb-0">
<div class="card-header border-bottom-0">
<h5 class="card-title my-1">{{ __('Stack trace') }}</h5>
</div>
</div>
<div v-if="loadingStacktrace" class="card">
<gl-loading-icon class="py-2" label="Fetching stack trace" :size="1" />
</div>
<stacktrace v-else :entries="stacktrace" />
</div>
</template>
import Vue from 'vue';
import SentryErrorStackTrace from './components/sentry_error_stack_trace.vue';
import store from '~/error_tracking/store';
export default function initSentryErrorStacktrace() {
const sentryErrorStackTraceEl = document.querySelector('#js-sentry-error-stack-trace');
if (sentryErrorStackTraceEl) {
const { issueStackTracePath } = sentryErrorStackTraceEl.dataset;
// eslint-disable-next-line no-new
new Vue({
el: sentryErrorStackTraceEl,
components: {
SentryErrorStackTrace,
},
store,
render: createElement =>
createElement('sentry-error-stack-trace', {
props: { issueStackTracePath },
}),
});
}
}
......@@ -71,6 +71,9 @@
= edited_time_ago_with_tooltip(@issue, placement: 'bottom', html_class: 'issue-edited-ago js-issue-edited-ago')
- if @issue.sentry_issue.present?
#js-sentry-error-stack-trace{ data: error_details_data(@project, @issue.sentry_issue.sentry_issue_identifier) }
= render_if_exists 'projects/issues/related_issues'
#js-related-merge-requests{ data: { endpoint: expose_path(api_v4_projects_issues_related_merge_requests_path(id: @project.id, issue_iid: @issue.iid)), project_namespace: @project.namespace.path, project_path: @project.path } }
......
---
title: Add stacktrace to issue created from the sentry error detail page
merge_request: 21438
author:
type: added
import { createLocalVue, shallowMount } from '@vue/test-utils';
import Vuex from 'vuex';
import { GlLoadingIcon } from '@gitlab/ui';
import Stacktrace from '~/error_tracking/components/stacktrace.vue';
import SentryErrorStackTrace from '~/sentry_error_stack_trace/components/sentry_error_stack_trace.vue';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('Sentry Error Stack Trace', () => {
let actions;
let getters;
let store;
let wrapper;
function mountComponent({
stubs = {
stacktrace: Stacktrace,
},
} = {}) {
wrapper = shallowMount(SentryErrorStackTrace, {
localVue,
stubs,
store,
propsData: {
issueStackTracePath: '/stacktrace',
},
});
}
beforeEach(() => {
actions = {
startPollingStacktrace: () => {},
};
getters = {
stacktrace: () => [{ context: [1, 2], lineNo: 53, filename: 'index.js' }],
};
const state = {
stacktraceData: {},
loadingStacktrace: true,
};
store = new Vuex.Store({
modules: {
details: {
namespaced: true,
actions,
getters,
state,
},
},
});
});
afterEach(() => {
if (wrapper) {
wrapper.destroy();
}
});
describe('loading', () => {
it('should show spinner while loading', () => {
mountComponent();
expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
expect(wrapper.find(Stacktrace).exists()).toBe(false);
});
});
describe('Stack trace', () => {
it('should show stacktrace', () => {
store.state.details.loadingStacktrace = false;
mountComponent({ stubs: {} });
expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
expect(wrapper.find(Stacktrace).exists()).toBe(true);
});
it('should not show stacktrace if it does not exist', () => {
store.state.details.loadingStacktrace = false;
expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
expect(wrapper.find(Stacktrace).exists()).toBe(false);
});
});
});
......@@ -130,4 +130,26 @@ describe 'projects/issues/show' do
expect(rendered).to have_selector('.status-box-open:not(.hidden)', text: 'Open')
end
end
context 'when the issue is related to a sentry error' do
it 'renders a stack trace' do
sentry_issue = double(:sentry_issue, sentry_issue_identifier: '1066622')
allow(issue).to receive(:sentry_issue).and_return(sentry_issue)
render
expect(rendered).to have_selector(
"#js-sentry-error-stack-trace"\
"[data-issue-stack-trace-path="\
"\"/#{project.full_path}/-/error_tracking/1066622/stack_trace.json\"]"
)
end
end
context 'when the issue is not related to a sentry error' do
it 'does not render a stack trace' do
render
expect(rendered).not_to have_selector('#js-sentry-error-stack-trace')
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment