Commit 3c19d44c authored by Himanshu Kapoor's avatar Himanshu Kapoor

Fix authored message when snippet is viewed publicly

Unauthenticated users cannot view author information for public
snippets. So for those cases, just display the creation time and omit
the author information. (Instead of omitting the entire message right
now due to a console error.)
parent c96920b5
...@@ -68,6 +68,11 @@ export default { ...@@ -68,6 +68,11 @@ export default {
snippetHasBinary() { snippetHasBinary() {
return Boolean(this.snippet.blobs.find(blob => blob.binary)); return Boolean(this.snippet.blobs.find(blob => blob.binary));
}, },
authoredMessage() {
return this.snippet.author
? __('Authored %{timeago} by %{author}')
: __('Authored %{timeago}');
},
personalSnippetActions() { personalSnippetActions() {
return [ return [
{ {
...@@ -178,8 +183,8 @@ export default { ...@@ -178,8 +183,8 @@ export default {
</span> </span>
<gl-icon :name="visibilityLevelIcon" :size="14" /> <gl-icon :name="visibilityLevelIcon" :size="14" />
</div> </div>
<div class="creator"> <div class="creator" data-testid="authored-message">
<gl-sprintf :message="__('Authored %{timeago} by %{author}')"> <gl-sprintf :message="authoredMessage">
<template #timeago> <template #timeago>
<time-ago-tooltip <time-ago-tooltip
:time="snippet.createdAt" :time="snippet.createdAt"
......
---
title: Display authored message correctly on public snippets viewed by unauthenticated users
merge_request: 38614
author:
type: fixed
...@@ -3459,6 +3459,9 @@ msgstr "" ...@@ -3459,6 +3459,9 @@ msgstr ""
msgid "Author: %{author_name}" msgid "Author: %{author_name}"
msgstr "" msgstr ""
msgid "Authored %{timeago}"
msgstr ""
msgid "Authored %{timeago} by %{author}" msgid "Authored %{timeago} by %{author}"
msgstr "" msgstr ""
......
...@@ -2,45 +2,18 @@ import SnippetHeader from '~/snippets/components/snippet_header.vue'; ...@@ -2,45 +2,18 @@ import SnippetHeader from '~/snippets/components/snippet_header.vue';
import DeleteSnippetMutation from '~/snippets/mutations/deleteSnippet.mutation.graphql'; import DeleteSnippetMutation from '~/snippets/mutations/deleteSnippet.mutation.graphql';
import { ApolloMutation } from 'vue-apollo'; import { ApolloMutation } from 'vue-apollo';
import { GlButton, GlModal } from '@gitlab/ui'; import { GlButton, GlModal } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { Blob, BinaryBlob } from 'jest/blob/components/mock_data'; import { Blob, BinaryBlob } from 'jest/blob/components/mock_data';
import waitForPromises from 'helpers/wait_for_promises';
describe('Snippet header component', () => { describe('Snippet header component', () => {
let wrapper; let wrapper;
const snippet = { let snippet;
id: 'gid://gitlab/PersonalSnippet/50', let mutationTypes;
title: 'The property of Thor', let mutationVariables;
visibilityLevel: 'private',
webUrl: 'http://personal.dev.null/42', let errorMsg;
userPermissions: { let err;
adminSnippet: true,
updateSnippet: true,
reportSnippet: false,
},
project: null,
author: {
name: 'Thor Odinson',
},
blobs: [Blob],
};
const mutationVariables = {
mutation: DeleteSnippetMutation,
variables: {
id: snippet.id,
},
};
const errorMsg = 'Foo bar';
const err = { message: errorMsg };
const resolveMutate = jest.fn(() =>
Promise.resolve({ data: { destroySnippet: { errors: [] } } }),
);
const rejectMutation = jest.fn(() => Promise.reject(err));
const mutationTypes = {
RESOLVE: resolveMutate,
REJECT: rejectMutation,
};
function createComponent({ function createComponent({
loading = false, loading = false,
...@@ -63,7 +36,7 @@ describe('Snippet header component', () => { ...@@ -63,7 +36,7 @@ describe('Snippet header component', () => {
mutate: mutationRes, mutate: mutationRes,
}; };
wrapper = shallowMount(SnippetHeader, { wrapper = mount(SnippetHeader, {
mocks: { $apollo }, mocks: { $apollo },
propsData: { propsData: {
snippet: { snippet: {
...@@ -76,6 +49,41 @@ describe('Snippet header component', () => { ...@@ -76,6 +49,41 @@ describe('Snippet header component', () => {
}); });
} }
beforeEach(() => {
snippet = {
id: 'gid://gitlab/PersonalSnippet/50',
title: 'The property of Thor',
visibilityLevel: 'private',
webUrl: 'http://personal.dev.null/42',
userPermissions: {
adminSnippet: true,
updateSnippet: true,
reportSnippet: false,
},
project: null,
author: {
name: 'Thor Odinson',
},
blobs: [Blob],
createdAt: new Date(Date.now() - 32 * 24 * 3600 * 1000).toISOString(),
};
mutationVariables = {
mutation: DeleteSnippetMutation,
variables: {
id: snippet.id,
},
};
errorMsg = 'Foo bar';
err = { message: errorMsg };
mutationTypes = {
RESOLVE: jest.fn(() => Promise.resolve({ data: { destroySnippet: { errors: [] } } })),
REJECT: jest.fn(() => Promise.reject(err)),
};
});
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
}); });
...@@ -85,6 +93,23 @@ describe('Snippet header component', () => { ...@@ -85,6 +93,23 @@ describe('Snippet header component', () => {
expect(wrapper.find('.detail-page-header').exists()).toBe(true); expect(wrapper.find('.detail-page-header').exists()).toBe(true);
}); });
it('renders a message showing snippet creation date and author', () => {
createComponent();
const text = wrapper.find('[data-testid="authored-message"]').text();
expect(text).toContain('Authored 1 month ago by');
expect(text).toContain('Thor Odinson');
});
it('renders a message showing only snippet creation date if author is null', () => {
snippet.author = null;
createComponent();
const text = wrapper.find('[data-testid="authored-message"]').text();
expect(text).toBe('Authored 1 month ago');
});
it('renders action buttons based on permissions', () => { it('renders action buttons based on permissions', () => {
createComponent({ createComponent({
permissions: { permissions: {
...@@ -163,14 +188,15 @@ describe('Snippet header component', () => { ...@@ -163,14 +188,15 @@ describe('Snippet header component', () => {
expect(mutationTypes.RESOLVE).toHaveBeenCalledWith(mutationVariables); expect(mutationTypes.RESOLVE).toHaveBeenCalledWith(mutationVariables);
}); });
it('sets error message if mutation fails', () => { it('sets error message if mutation fails', async () => {
createComponent({ mutationRes: mutationTypes.REJECT }); createComponent({ mutationRes: mutationTypes.REJECT });
expect(Boolean(wrapper.vm.errorMessage)).toBe(false); expect(Boolean(wrapper.vm.errorMessage)).toBe(false);
wrapper.vm.deleteSnippet(); wrapper.vm.deleteSnippet();
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.errorMessage).toEqual(errorMsg); await waitForPromises();
});
expect(wrapper.vm.errorMessage).toEqual(errorMsg);
}); });
describe('in case of successful mutation, closes modal and redirects to correct listing', () => { describe('in case of successful mutation, closes modal and redirects to correct listing', () => {
......
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