Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-02-08 15:10:06 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-02-08 15:10:06 +0300
commitd0aeb5df3d6b06165355b023a25b79c7bd74a27d (patch)
tree7b5d3ff0f0ac5c124aa8626aeb4a0682d99a17c2 /spec
parent9ccf40d15a14e9ccf613701ba7e3d5d250961345 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/concerns/send_file_upload_spec.rb15
-rw-r--r--spec/features/groups_spec.rb27
-rw-r--r--spec/features/merge_request/user_sees_discussions_navigation_spec.rb3
-rw-r--r--spec/finders/ci/pipelines_finder_spec.rb4
-rw-r--r--spec/fixtures/emails/html_only.eml45
-rw-r--r--spec/fixtures/lib/gitlab/email/basic.html72
-rw-r--r--spec/frontend/admin/topics/components/topic_select_spec.js122
-rw-r--r--spec/frontend/pages/shared/wikis/components/wiki_form_spec.js11
-rw-r--r--spec/frontend/pipelines/pipelines_spec.js20
-rw-r--r--spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js16
-rw-r--r--spec/frontend/work_items/components/work_item_labels_spec.js40
-rw-r--r--spec/frontend/work_items/mock_data.js13
-rw-r--r--spec/helpers/appearances_helper_spec.rb45
-rw-r--r--spec/lib/gitlab/bare_repository_import/importer_spec.rb5
-rw-r--r--spec/lib/gitlab/bitbucket_import/project_creator_spec.rb4
-rw-r--r--spec/lib/gitlab/email/html_to_markdown_parser_spec.rb46
-rw-r--r--spec/lib/gitlab/email/reply_parser_spec.rb64
-rw-r--r--spec/lib/gitlab/gitlab_import/project_creator_spec.rb4
-rw-r--r--spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb4
-rw-r--r--spec/lib/gitlab/import_export/project/relation_factory_spec.rb76
-rw-r--r--spec/lib/gitlab/legacy_github_import/project_creator_spec.rb2
-rw-r--r--spec/models/appearance_spec.rb14
-rw-r--r--spec/models/ci/pipeline_spec.rb4
-rw-r--r--spec/policies/group_policy_spec.rb36
-rw-r--r--spec/requests/api/draft_notes_spec.rb47
-rw-r--r--spec/requests/pwa_controller_spec.rb85
26 files changed, 727 insertions, 97 deletions
diff --git a/spec/controllers/concerns/send_file_upload_spec.rb b/spec/controllers/concerns/send_file_upload_spec.rb
index 0b24387483b..6acbff6e745 100644
--- a/spec/controllers/concerns/send_file_upload_spec.rb
+++ b/spec/controllers/concerns/send_file_upload_spec.rb
@@ -54,17 +54,18 @@ RSpec.describe SendFileUpload do
FileUtils.rm_f(temp_file)
end
- shared_examples 'handles image resize requests' do
+ shared_examples 'handles image resize requests' do |mount|
let(:headers) { double }
let(:image_requester) { build(:user) }
let(:image_owner) { build(:user) }
+ let(:width) { mount == :pwa_icon ? 192 : 64 }
let(:params) do
{ attachment: 'avatar.png' }
end
before do
allow(uploader).to receive(:image_safe_for_scaling?).and_return(true)
- allow(uploader).to receive(:mounted_as).and_return(:avatar)
+ allow(uploader).to receive(:mounted_as).and_return(mount)
allow(controller).to receive(:headers).and_return(headers)
# both of these are valid cases, depending on whether we are dealing with
@@ -99,11 +100,11 @@ RSpec.describe SendFileUpload do
context 'with valid width parameter' do
it 'renders OK with workhorse command header' do
expect(controller).not_to receive(:send_file)
- expect(controller).to receive(:params).at_least(:once).and_return(width: '64')
+ expect(controller).to receive(:params).at_least(:once).and_return(width: width.to_s)
expect(controller).to receive(:head).with(:ok)
expect(Gitlab::Workhorse).to receive(:send_scaled_image)
- .with(a_string_matching('^(/.+|https://.+)'), 64, 'image/png')
+ .with(a_string_matching('^(/.+|https://.+)'), width, 'image/png')
.and_return([Gitlab::Workhorse::SEND_DATA_HEADER, "send-scaled-img:faux"])
expect(headers).to receive(:store).with(Gitlab::Workhorse::SEND_DATA_HEADER, "send-scaled-img:faux")
@@ -168,7 +169,8 @@ RSpec.describe SendFileUpload do
subject
end
- it_behaves_like 'handles image resize requests'
+ it_behaves_like 'handles image resize requests', :avatar
+ it_behaves_like 'handles image resize requests', :pwa_icon
end
context 'with inline image' do
@@ -273,7 +275,8 @@ RSpec.describe SendFileUpload do
end
end
- it_behaves_like 'handles image resize requests'
+ it_behaves_like 'handles image resize requests', :avatar
+ it_behaves_like 'handles image resize requests', :pwa_icon
end
context 'when CDN-enabled remote file is used' do
diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb
index 8806d1c2219..e3ec28f9c65 100644
--- a/spec/features/groups_spec.rb
+++ b/spec/features/groups_spec.rb
@@ -510,6 +510,33 @@ RSpec.describe 'Group', feature_category: :subgroups do
end
end
end
+
+ context 'when in a private group' do
+ before do
+ group.update!(
+ visibility_level: Gitlab::VisibilityLevel::PRIVATE,
+ project_creation_level: Gitlab::Access::MAINTAINER_PROJECT_ACCESS
+ )
+ end
+
+ context 'when visibility levels have been restricted to private only by an administrator' do
+ before do
+ stub_application_setting(
+ restricted_visibility_levels: [
+ Gitlab::VisibilityLevel::PRIVATE
+ ]
+ )
+ end
+
+ it 'does not display the "New project" button' do
+ visit group_path(group)
+
+ page.within '[data-testid="group-buttons"]' do
+ expect(page).not_to have_link('New project')
+ end
+ end
+ end
+ end
end
def remove_with_confirm(button_text, confirm_with)
diff --git a/spec/features/merge_request/user_sees_discussions_navigation_spec.rb b/spec/features/merge_request/user_sees_discussions_navigation_spec.rb
index 9d3046a9a72..4beddb8c8bc 100644
--- a/spec/features/merge_request/user_sees_discussions_navigation_spec.rb
+++ b/spec/features/merge_request/user_sees_discussions_navigation_spec.rb
@@ -92,7 +92,8 @@ RSpec.describe 'Merge request > User sees discussions navigation', :js, feature_
page.execute_script("window.scrollTo(0,0)")
end
- it 'excludes resolved threads during navigation' do
+ it 'excludes resolved threads during navigation',
+ quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/383687' do
goto_next_thread
goto_next_thread
goto_next_thread
diff --git a/spec/finders/ci/pipelines_finder_spec.rb b/spec/finders/ci/pipelines_finder_spec.rb
index 9ce3becf013..8773fbccdfc 100644
--- a/spec/finders/ci/pipelines_finder_spec.rb
+++ b/spec/finders/ci/pipelines_finder_spec.rb
@@ -246,9 +246,9 @@ RSpec.describe Ci::PipelinesFinder do
let_it_be(:pipeline) { create(:ci_pipeline, project: project, name: 'Build pipeline') }
let_it_be(:pipeline_other) { create(:ci_pipeline, project: project, name: 'Some other pipeline') }
- let(:params) { { name: 'build Pipeline' } }
+ let(:params) { { name: 'Build pipeline' } }
- it 'performs case insensitive compare' do
+ it 'performs exact compare' do
is_expected.to contain_exactly(pipeline)
end
diff --git a/spec/fixtures/emails/html_only.eml b/spec/fixtures/emails/html_only.eml
new file mode 100644
index 00000000000..22a1a431771
--- /dev/null
+++ b/spec/fixtures/emails/html_only.eml
@@ -0,0 +1,45 @@
+Delivered-To: reply@discourse.org
+Return-Path: <walter.white@googlemail.com>
+MIME-Version: 1.0
+In-Reply-To: <topic/22638/86406@meta.discourse.org>
+References: <topic/22638@meta.discourse.org>
+ <topic/22638/86406@meta.discourse.org>
+Date: Fri, 28 Nov 2014 12:36:49 -0800
+Subject: Re: [Discourse Meta] [Lounge] Testing default email replies
+From: Walter White <walter.white@googlemail.com>
+To: Discourse Meta <reply@discourse.org>
+Content-Type: multipart/related; boundary=001a11c2e04e6544f30508f138ba
+
+--001a11c2e04e6544f30508f138ba
+Content-Type: text/html; charset=UTF-8
+Content-Transfer-Encoding: quoted-printable
+
+<div dir=3D"ltr"><div>### This is a reply from standard GMail in Google Chr=
+ome.</div><div><br></div><div>The quick brown fox jumps over the lazy dog. =
+The quick brown fox jumps over the lazy dog. The quick brown fox jumps over=
+ the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown=
+ fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. =
+The quick brown fox jumps over the lazy dog. The quick brown fox jumps over=
+ the lazy dog.=C2=A0</div><div><br></div><div>Here&#39;s some **bold** text=
+, <strong>strong</strong> text and <em>italic</em> in Markdown.</div><div><=
+br></div><div>Here&#39;s a link <a href=3D"http://example.com">http://examp=
+le.com</a></div></div><div class=3D"gmail_extra"><br>Here&#39;s an img <i=
+mg class="header__logoSize_110px" src="http://img.png" hspace="0" vspac=
+e="0" border="0" style="display:block; width:138px; max-width:138px;" width=
+="138" alt="Miro"><details><summary>One</summary> Some details</details>
+<details><summary>Two</summary> Some details</details></div>
+
+<table style=3D"margin-bottom:25px" cellspacing=3D"0" cellpadding=3D"0" bor=
+der=3D"0">
+ <tbody>
+ <tr>
+ <td style=3D"padding-top:5px" colspan=3D"2">
+ <p style=3D"margin-top:0;border:0">Test reply.</p>
+ <p style=3D"margin-top:0;border:0">First paragraph.</p>
+ <p style=3D"margin-top:0;border:0">Second paragraph.</p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+--001a11c2e04e6544f30508f138ba--
diff --git a/spec/fixtures/lib/gitlab/email/basic.html b/spec/fixtures/lib/gitlab/email/basic.html
new file mode 100644
index 00000000000..807b23c46e3
--- /dev/null
+++ b/spec/fixtures/lib/gitlab/email/basic.html
@@ -0,0 +1,72 @@
+<html>
+ <title>Ignored Title</title>
+ <body>
+ <h1>Hello, World!</h1>
+
+ This is some e-mail content.
+ Even though it has whitespace and newlines, the e-mail converter
+ will handle it correctly.
+
+ <p><em>Even</em> mismatched tags.</p>
+
+ <div>A div</div>
+ <div>Another div</div>
+ <div>A div<div><strong>within</strong> a div</div></div>
+
+ <p>Another line<br />Yet another line</p>
+
+ <a href="http://foo.com">A link</a>
+
+ <p><details><summary>One</summary>Some details</details></p>
+
+ <p><details><summary>Two</summary>Some details</details></p>
+
+ <img class="header__logoSize_110px" src="http://img.png" hspace="0" vspace="0" border="0"
+ style="display:block; width:138px; max-width:138px;" width="138" alt="Miro">
+
+ <table>
+ <thead>
+ <tr>
+ <th>Col A</th>
+ <th>Col B</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ Data A1
+ </td>
+ <td>
+ Data B1
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Data A2
+ </td>
+ <td>
+ Data B2
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Data A3
+ </td>
+ <td>
+ Data B4
+ </td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <td>
+ Total A
+ </td>
+ <td>
+ Total B
+ </td>
+ </tr>
+ </tfoot>
+ </table>
+ </body>
+</html>
diff --git a/spec/frontend/admin/topics/components/topic_select_spec.js b/spec/frontend/admin/topics/components/topic_select_spec.js
index f61af6203f0..738cbd88c4c 100644
--- a/spec/frontend/admin/topics/components/topic_select_spec.js
+++ b/spec/frontend/admin/topics/components/topic_select_spec.js
@@ -1,39 +1,66 @@
-import { GlAvatarLabeled, GlDropdown, GlDropdownItem } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
+import { GlAvatarLabeled, GlCollapsibleListbox, GlListboxItem } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
import TopicSelect from '~/admin/topics/components/topic_select.vue';
+import searchProjectTopics from '~/graphql_shared/queries/project_topics_search.query.graphql';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
const mockTopics = [
- { id: 1, name: 'topic1', title: 'Topic 1', avatarUrl: 'avatar.com/topic1.png' },
- { id: 2, name: 'GitLab', title: 'GitLab', avatarUrl: 'avatar.com/GitLab.png' },
+ {
+ id: 'gid://gitlab/Projects::Topic/6',
+ name: 'topic1',
+ title: 'Topic 1',
+ avatarUrl: 'avatar.com/topic1.png',
+ __typename: 'Topic',
+ },
+ {
+ id: 'gid://gitlab/Projects::Topic/5',
+ name: 'gitlab',
+ title: 'GitLab',
+ avatarUrl: 'avatar.com/GitLab.png',
+ __typename: 'Topic',
+ },
];
+const mockTopicsQueryResponse = {
+ data: {
+ topics: {
+ nodes: mockTopics,
+ __typename: 'TopicConnection',
+ },
+ },
+};
+
describe('TopicSelect', () => {
let wrapper;
+ const mockSearchTopicsSuccess = jest.fn().mockResolvedValue(mockTopicsQueryResponse);
+
+ const findListbox = () => wrapper.findComponent(GlCollapsibleListbox);
+ const findAllListboxItems = () => wrapper.findAllComponents(GlListboxItem);
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
+ function createMockApolloProvider({ mockSearchTopicsQuery = mockSearchTopicsSuccess } = {}) {
+ Vue.use(VueApollo);
+
+ return createMockApollo([[searchProjectTopics, mockSearchTopicsQuery]]);
+ }
- function createComponent(props = {}) {
- wrapper = shallowMount(TopicSelect, {
+ function createComponent({ props = {}, mockApollo } = {}) {
+ wrapper = mount(TopicSelect, {
+ apolloProvider: mockApollo || createMockApolloProvider(),
propsData: props,
data() {
return {
topics: mockTopics,
- search: '',
};
},
- mocks: {
- $apollo: {
- queries: {
- topics: { loading: false },
- },
- },
- },
});
}
afterEach(() => {
wrapper.destroy();
+ jest.clearAllMocks();
});
it('mounts', () => {
@@ -57,17 +84,27 @@ describe('TopicSelect', () => {
it('renders default text if no selected topic', () => {
createComponent();
- expect(findDropdown().props('text')).toBe('Select a topic');
+ expect(findListbox().props('toggleText')).toBe('Select a topic');
});
it('renders selected topic', () => {
- createComponent({ selectedTopic: mockTopics[0] });
+ const mockTopic = mockTopics[0];
- expect(findDropdown().props('text')).toBe('topic1');
+ createComponent({
+ props: {
+ selectedTopic: mockTopic,
+ },
+ });
+
+ expect(findListbox().props('toggleText')).toBe(mockTopic.name);
});
it('renders label', () => {
- createComponent({ labelText: 'my label' });
+ createComponent({
+ props: {
+ labelText: 'my label',
+ },
+ });
expect(wrapper.find('label').text()).toBe('my label');
});
@@ -75,17 +112,52 @@ describe('TopicSelect', () => {
it('renders dropdown items', () => {
createComponent();
- const dropdownItems = findAllDropdownItems();
+ const listboxItems = findAllListboxItems();
+
+ expect(listboxItems.at(0).findComponent(GlAvatarLabeled).props('label')).toBe('Topic 1');
+ expect(listboxItems.at(1).findComponent(GlAvatarLabeled).props('label')).toBe('GitLab');
+ });
+
+ it('dropdown `toggledAriaLabelledBy` prop is not set if `labelText` prop is null', () => {
+ createComponent();
- expect(dropdownItems.at(0).findComponent(GlAvatarLabeled).props('label')).toBe('Topic 1');
- expect(dropdownItems.at(1).findComponent(GlAvatarLabeled).props('label')).toBe('GitLab');
+ expect(findListbox().props('toggle-aria-labelled-by')).toBe(undefined);
});
- it('emits `click` event when topic selected', () => {
+ it('emits `click` event when topic selected', async () => {
createComponent();
- findAllDropdownItems().at(0).vm.$emit('click');
+ await findAllListboxItems().at(0).trigger('click');
expect(wrapper.emitted('click')).toEqual([[mockTopics[0]]]);
});
+
+ describe('when searching a topic', () => {
+ const searchTopic = (searchTerm) => findListbox().vm.$emit('search', searchTerm);
+ const mockSearchTerm = 'gitl';
+
+ it('toggles loading state', async () => {
+ createComponent();
+ jest.runOnlyPendingTimers();
+
+ await searchTopic(mockSearchTerm);
+
+ expect(findListbox().props('searching')).toBe(true);
+
+ await waitForPromises();
+
+ expect(findListbox().props('searching')).toBe(false);
+ });
+
+ it('fetches topics matching search string', async () => {
+ createComponent();
+
+ await searchTopic(mockSearchTerm);
+ jest.runOnlyPendingTimers();
+
+ expect(mockSearchTopicsSuccess).toHaveBeenCalledWith({
+ search: mockSearchTerm,
+ });
+ });
+ });
});
diff --git a/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js b/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
index 67d0fbdd9d1..ffcfd1d9f78 100644
--- a/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
+++ b/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
@@ -110,17 +110,22 @@ describe('WikiForm', () => {
it('displays markdown editor', () => {
createWrapper({ persisted: true });
- expect(findMarkdownEditor().props()).toEqual(
+ const markdownEditor = findMarkdownEditor();
+
+ expect(markdownEditor.props()).toEqual(
expect.objectContaining({
value: pageInfoPersisted.content,
renderMarkdownPath: pageInfoPersisted.markdownPreviewPath,
markdownDocsPath: pageInfoPersisted.markdownHelpPath,
uploadsPath: pageInfoPersisted.uploadsPath,
autofocus: pageInfoPersisted.persisted,
- formFieldId: 'wiki_content',
- formFieldName: 'wiki[content]',
}),
);
+
+ expect(markdownEditor.props('formFieldProps')).toMatchObject({
+ id: 'wiki_content',
+ name: 'wiki[content]',
+ });
});
it.each`
diff --git a/spec/frontend/pipelines/pipelines_spec.js b/spec/frontend/pipelines/pipelines_spec.js
index 518539d97ba..2523b901506 100644
--- a/spec/frontend/pipelines/pipelines_spec.js
+++ b/spec/frontend/pipelines/pipelines_spec.js
@@ -449,6 +449,26 @@ describe('Pipelines', () => {
`${window.location.pathname}?page=2&scope=all`,
);
});
+
+ it('should reset page to 1 when filtering pipelines', () => {
+ expect(window.history.pushState).toHaveBeenCalledTimes(1);
+ expect(window.history.pushState).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.anything(),
+ `${window.location.pathname}?page=2&scope=all`,
+ );
+
+ findFilteredSearch().vm.$emit('submit', [
+ { type: 'status', value: { data: 'success', operator: '=' } },
+ ]);
+
+ expect(window.history.pushState).toHaveBeenCalledTimes(2);
+ expect(window.history.pushState).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.anything(),
+ `${window.location.pathname}?page=1&scope=all&status=success`,
+ );
+ });
});
});
diff --git a/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js b/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js
index e3df2cde1c1..12eda284aea 100644
--- a/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js
@@ -36,10 +36,12 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
quickActionsDocsPath,
enableAutocomplete,
enablePreview,
- formFieldId,
- formFieldName,
- formFieldPlaceholder,
- formFieldAriaLabel,
+ formFieldProps: {
+ id: formFieldId,
+ name: formFieldName,
+ placeholder: formFieldPlaceholder,
+ 'aria-label': formFieldAriaLabel,
+ },
...propsData,
},
stubs: {
@@ -95,6 +97,12 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
expect(findTextarea().element.value).toBe(value);
});
+ it('fails to render if textarea id and name is not passed', () => {
+ expect(() => {
+ buildWrapper({ propsData: { formFieldProps: {} } });
+ }).toThrow('Invalid prop: custom validator check failed for prop "formFieldProps"');
+ });
+
it(`emits ${EDITING_MODE_CONTENT_EDITOR} event when enableContentEditor emitted from markdown editor`, async () => {
buildWrapper();
diff --git a/spec/frontend/work_items/components/work_item_labels_spec.js b/spec/frontend/work_items/components/work_item_labels_spec.js
index 083bb5bc4a4..0b6ab5c3290 100644
--- a/spec/frontend/work_items/components/work_item_labels_spec.js
+++ b/spec/frontend/work_items/components/work_item_labels_spec.js
@@ -85,7 +85,7 @@ describe('WorkItemLabels component', () => {
it('focuses token selector on token selector input event', async () => {
createComponent();
findTokenSelector().vm.$emit('input', [mockLabels[0]]);
- await nextTick();
+ await waitForPromises();
expect(findEmptyState().exists()).toBe(false);
expect(findTokenSelector().element.contains(document.activeElement)).toBe(true);
@@ -189,6 +189,23 @@ describe('WorkItemLabels component', () => {
);
});
+ it('adds new labels to the end', async () => {
+ const response = workItemResponseFactory({ labels: [mockLabels[1]] });
+ const workItemQueryHandler = jest.fn().mockResolvedValue(response);
+ createComponent({
+ workItemQueryHandler,
+ updateWorkItemMutationHandler: successUpdateWorkItemMutationHandler,
+ });
+ await waitForPromises();
+
+ findTokenSelector().vm.$emit('input', [mockLabels[0]]);
+ await waitForPromises();
+
+ const labels = findTokenSelector().props('selectedTokens');
+ expect(labels[0]).toMatchObject(mockLabels[1]);
+ expect(labels[1]).toMatchObject(mockLabels[0]);
+ });
+
describe('when clicking outside the token selector', () => {
it('calls a mutation with correct variables', () => {
createComponent();
@@ -205,9 +222,7 @@ describe('WorkItemLabels component', () => {
});
it('emits an error and resets labels if mutation was rejected', async () => {
- const workItemQueryHandler = jest.fn().mockResolvedValue(workItemResponseFactory());
-
- createComponent({ updateWorkItemMutationHandler: errorHandler, workItemQueryHandler });
+ createComponent({ updateWorkItemMutationHandler: errorHandler });
await waitForPromises();
@@ -224,6 +239,23 @@ describe('WorkItemLabels component', () => {
expect(updatedLabels).toEqual(initialLabels);
});
+ it('does not make server request if no labels added or removed', async () => {
+ const updateWorkItemMutationHandler = jest
+ .fn()
+ .mockResolvedValue(updateWorkItemMutationResponse);
+
+ createComponent({ updateWorkItemMutationHandler });
+
+ await waitForPromises();
+
+ findTokenSelector().vm.$emit('input', []);
+ findTokenSelector().vm.$emit('blur', new FocusEvent({ relatedTarget: null }));
+
+ await waitForPromises();
+
+ expect(updateWorkItemMutationHandler).not.toHaveBeenCalled();
+ });
+
it('has a subscription', async () => {
createComponent();
diff --git a/spec/frontend/work_items/mock_data.js b/spec/frontend/work_items/mock_data.js
index 5b331c016a9..d6b2b5a1981 100644
--- a/spec/frontend/work_items/mock_data.js
+++ b/spec/frontend/work_items/mock_data.js
@@ -215,6 +215,14 @@ export const updateWorkItemMutationResponse = {
nodes: [mockAssignees[0]],
},
},
+ {
+ __typename: 'WorkItemWidgetLabels',
+ type: 'LABELS',
+ allowsScopedLabels: false,
+ labels: {
+ nodes: mockLabels,
+ },
+ },
],
},
},
@@ -279,7 +287,6 @@ export const workItemResponseFactory = ({
allowsMultipleAssignees = true,
assigneesWidgetPresent = true,
datesWidgetPresent = true,
- labelsWidgetPresent = true,
weightWidgetPresent = true,
progressWidgetPresent = true,
milestoneWidgetPresent = true,
@@ -288,6 +295,8 @@ export const workItemResponseFactory = ({
notesWidgetPresent = true,
confidential = false,
canInviteMembers = false,
+ labelsWidgetPresent = true,
+ labels = mockLabels,
allowsScopedLabels = false,
lastEditedAt = null,
lastEditedBy = null,
@@ -350,7 +359,7 @@ export const workItemResponseFactory = ({
type: 'LABELS',
allowsScopedLabels,
labels: {
- nodes: mockLabels,
+ nodes: labels,
},
}
: { type: 'MOCK TYPE' },
diff --git a/spec/helpers/appearances_helper_spec.rb b/spec/helpers/appearances_helper_spec.rb
index 3c698fb2d41..2b0192d24b3 100644
--- a/spec/helpers/appearances_helper_spec.rb
+++ b/spec/helpers/appearances_helper_spec.rb
@@ -10,6 +10,51 @@ RSpec.describe AppearancesHelper do
allow(helper).to receive(:current_user).and_return(user)
end
+ describe 'pwa icon scaled' do
+ before do
+ stub_config_setting(relative_url_root: '/relative_root')
+ end
+
+ shared_examples 'gets icon path' do |width|
+ let!(:width) { width }
+
+ it 'returns path of icon' do
+ expect(helper.appearance_pwa_icon_path_scaled(width)).to match(result)
+ end
+ end
+
+ context 'with custom icon' do
+ let!(:appearance) { create(:appearance, :with_pwa_icon) }
+ let!(:result) { "/relative_root/uploads/-/system/appearance/pwa_icon/#{appearance.id}/dk.png?width=#{width}" }
+
+ it_behaves_like 'gets icon path', 192
+ it_behaves_like 'gets icon path', 512
+ end
+
+ context 'with default icon' do
+ let!(:result) { "/relative_root/-/pwa-icons/logo-#{width}.png" }
+
+ it_behaves_like 'gets icon path', 192
+ it_behaves_like 'gets icon path', 512
+ end
+
+ it 'returns path of maskable logo' do
+ expect(helper.appearance_maskable_logo).to match('/relative_root/-/pwa-icons/maskable-logo.png')
+ end
+
+ context 'with wrong input' do
+ let!(:result) { nil }
+
+ it_behaves_like 'gets icon path', 19200
+ end
+
+ context 'when path is append to root' do
+ it 'appends root and path' do
+ expect(helper.append_root_path('/works_just_fine')).to match('/relative_root/works_just_fine')
+ end
+ end
+ end
+
describe '#appearance_pwa_name' do
it 'returns the default value' do
create(:appearance)
diff --git a/spec/lib/gitlab/bare_repository_import/importer_spec.rb b/spec/lib/gitlab/bare_repository_import/importer_spec.rb
index 3a885d70eb4..1fb442a74fb 100644
--- a/spec/lib/gitlab/bare_repository_import/importer_spec.rb
+++ b/spec/lib/gitlab/bare_repository_import/importer_spec.rb
@@ -73,9 +73,8 @@ RSpec.describe Gitlab::BareRepositoryImport::Importer do
end
it 'does not schedule an import' do
- expect_next_instance_of(Project) do |instance|
- expect(instance).not_to receive(:import_schedule)
- end
+ project = Project.find_by_full_path(project_path)
+ expect(project).not_to receive(:import_schedule)
importer.create_project_if_needed
end
diff --git a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb
index 236e04a041b..95b1661ac99 100644
--- a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb
@@ -27,8 +27,8 @@ RSpec.describe Gitlab::BitbucketImport::ProjectCreator do
end
it 'creates project' do
- expect_next_instance_of(Project) do |project|
- expect(project).to receive(:add_import_job)
+ allow_next_instances_of(Project, 2) do |project|
+ allow(project).to receive(:add_import_job)
end
project_creator = described_class.new(repo, 'vim', namespace, user, access_params)
diff --git a/spec/lib/gitlab/email/html_to_markdown_parser_spec.rb b/spec/lib/gitlab/email/html_to_markdown_parser_spec.rb
new file mode 100644
index 00000000000..fe585d47d59
--- /dev/null
+++ b/spec/lib/gitlab/email/html_to_markdown_parser_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Email::HtmlToMarkdownParser, feature_category: :service_desk do
+ subject { described_class.convert(html) }
+
+ describe '.convert' do
+ let(:html) { fixture_file("lib/gitlab/email/basic.html") }
+
+ it 'parses html correctly' do
+ expect(subject)
+ .to eq(
+ <<-BODY.strip_heredoc.chomp
+ Hello, World!
+ This is some e-mail content. Even though it has whitespace and newlines, the e-mail converter will handle it correctly.
+ *Even* mismatched tags.
+ A div
+ Another div
+ A div
+ **within** a div
+
+ Another line
+ Yet another line
+ [A link](http://foo.com)
+ <details>
+ <summary>
+ One</summary>
+ Some details</details>
+
+ <details>
+ <summary>
+ Two</summary>
+ Some details</details>
+
+ ![Miro](http://img.png)
+ Col A Col B
+ Data A1 Data B1
+ Data A2 Data B2
+ Data A3 Data B4
+ Total A Total B
+ BODY
+ )
+ end
+ end
+end
diff --git a/spec/lib/gitlab/email/reply_parser_spec.rb b/spec/lib/gitlab/email/reply_parser_spec.rb
index 10ffb420508..e4c68dbba92 100644
--- a/spec/lib/gitlab/email/reply_parser_spec.rb
+++ b/spec/lib/gitlab/email/reply_parser_spec.rb
@@ -188,6 +188,70 @@ RSpec.describe Gitlab::Email::ReplyParser do
)
end
+ context 'properly renders email reply from gmail web client' do
+ context 'when feature flag is enabled' do
+ it do
+ expect(test_parse_body(fixture_file("emails/html_only.eml")))
+ .to eq(
+ <<-BODY.strip_heredoc.chomp
+ ### This is a reply from standard GMail in Google Chrome.
+
+ The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.
+
+ Here's some **bold** text, **strong** text and *italic* in Markdown.
+
+ Here's a link http://example.com
+
+ Here's an img ![Miro](http://img.png)<details>
+ <summary>
+ One</summary>
+ Some details</details>
+
+ <details>
+ <summary>
+ Two</summary>
+ Some details</details>
+
+ Test reply.
+
+ First paragraph.
+
+ Second paragraph.
+ BODY
+ )
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(service_desk_html_to_text_email_handler: false)
+ end
+
+ it do
+ expect(test_parse_body(fixture_file("emails/html_only.eml")))
+ .to eq(
+ <<-BODY.strip_heredoc.chomp
+ ### This is a reply from standard GMail in Google Chrome.
+
+ The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.
+
+ Here's some **bold** text, strong text and italic in Markdown.
+
+ Here's a link http://example.com
+
+ Here's an img [Miro]One Some details Two Some details
+
+ Test reply.
+
+ First paragraph.
+
+ Second paragraph.
+ BODY
+ )
+ end
+ end
+ end
+
it "properly renders email reply from iOS default mail client" do
expect(test_parse_body(fixture_file("emails/ios_default.eml")))
.to eq(
diff --git a/spec/lib/gitlab/gitlab_import/project_creator_spec.rb b/spec/lib/gitlab/gitlab_import/project_creator_spec.rb
index 53bf1db3438..59a98987f7d 100644
--- a/spec/lib/gitlab/gitlab_import/project_creator_spec.rb
+++ b/spec/lib/gitlab/gitlab_import/project_creator_spec.rb
@@ -24,8 +24,8 @@ RSpec.describe Gitlab::GitlabImport::ProjectCreator do
end
it 'creates project' do
- expect_next_instance_of(Project) do |project|
- expect(project).to receive(:add_import_job)
+ allow_next_instance_of(Project) do |project|
+ allow(project).to receive(:add_import_job)
end
project_creator = described_class.new(repo, namespace, user, access_params)
diff --git a/spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb b/spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb
index f853bccc115..103d3512e8b 100644
--- a/spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb
+++ b/spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb
@@ -295,9 +295,9 @@ RSpec.describe Gitlab::ImportExport::Json::StreamingSerializer, feature_category
end
end
- it_behaves_like 'record with exportable associations', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/390356' do
+ it_behaves_like 'record with exportable associations' do
let(:expected_issue) do
- issue_hash[many_relation].delete_at(1)
+ issue_hash[many_relation].delete_if { |record| record['id'] == link2.id }
issue_hash.to_json(options)
end
end
diff --git a/spec/lib/gitlab/import_export/project/relation_factory_spec.rb b/spec/lib/gitlab/import_export/project/relation_factory_spec.rb
index 936c63fd6cd..d133f54ade5 100644
--- a/spec/lib/gitlab/import_export/project/relation_factory_spec.rb
+++ b/spec/lib/gitlab/import_export/project/relation_factory_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::ImportExport::Project::RelationFactory, :use_clean_rails_memory_store_caching do
+RSpec.describe Gitlab::ImportExport::Project::RelationFactory, :use_clean_rails_memory_store_caching, feature_category: :importers do
let(:group) { create(:group).tap { |g| g.add_maintainer(importer_user) } }
let(:project) { create(:project, :repository, group: group) }
let(:members_mapper) { double('members_mapper').as_null_object }
@@ -418,21 +418,73 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory, :use_clean_rails_
end
end
- context 'merge request access level object' do
- let(:relation_sym) { :'ProtectedBranch::MergeAccessLevel' }
- let(:relation_hash) { { 'access_level' => 30, 'created_at' => '2022-03-29T09:53:13.457Z', 'updated_at' => '2022-03-29T09:54:13.457Z' } }
+ describe 'protected branch access levels' do
+ shared_examples 'access levels' do
+ let(:relation_hash) { { 'access_level' => access_level, 'created_at' => '2022-03-29T09:53:13.457Z', 'updated_at' => '2022-03-29T09:54:13.457Z' } }
- it 'sets access level to maintainer' do
- expect(created_object.access_level).to equal(Gitlab::Access::MAINTAINER)
+ context 'when access level is no one' do
+ let(:access_level) { Gitlab::Access::NO_ACCESS }
+
+ it 'keeps no one access level' do
+ expect(created_object.access_level).to equal(access_level)
+ end
+ end
+
+ context 'when access level is below maintainer' do
+ let(:access_level) { Gitlab::Access::DEVELOPER }
+
+ it 'sets access level to maintainer' do
+ expect(created_object.access_level).to equal(Gitlab::Access::MAINTAINER)
+ end
+ end
+
+ context 'when access level is above maintainer' do
+ let(:access_level) { Gitlab::Access::OWNER }
+
+ it 'sets access level to maintainer' do
+ expect(created_object.access_level).to equal(Gitlab::Access::MAINTAINER)
+ end
+ end
+
+ describe 'root ancestor membership' do
+ let(:access_level) { Gitlab::Access::DEVELOPER }
+
+ context 'when importer user is root group owner' do
+ let(:importer_user) { create(:user) }
+
+ it 'keeps access level as is' do
+ group.add_owner(importer_user)
+
+ expect(created_object.access_level).to equal(access_level)
+ end
+ end
+
+ context 'when user membership in root group is missing' do
+ it 'sets access level to maintainer' do
+ group.members.delete_all
+
+ expect(created_object.access_level).to equal(Gitlab::Access::MAINTAINER)
+ end
+ end
+
+ context 'when root ancestor is not a group' do
+ it 'sets access level to maintainer' do
+ expect(created_object.access_level).to equal(Gitlab::Access::MAINTAINER)
+ end
+ end
+ end
+ end
+
+ describe 'merge access level' do
+ let(:relation_sym) { :'ProtectedBranch::MergeAccessLevel' }
+
+ include_examples 'access levels'
end
- end
- context 'push access level object' do
- let(:relation_sym) { :'ProtectedBranch::PushAccessLevel' }
- let(:relation_hash) { { 'access_level' => 30, 'created_at' => '2022-03-29T09:53:13.457Z', 'updated_at' => '2022-03-29T09:54:13.457Z' } }
+ describe 'push access level' do
+ let(:relation_sym) { :'ProtectedBranch::PushAccessLevel' }
- it 'sets access level to maintainer' do
- expect(created_object.access_level).to equal(Gitlab::Access::MAINTAINER)
+ include_examples 'access levels'
end
end
end
diff --git a/spec/lib/gitlab/legacy_github_import/project_creator_spec.rb b/spec/lib/gitlab/legacy_github_import/project_creator_spec.rb
index 17ecd183ac9..5df44bfb83c 100644
--- a/spec/lib/gitlab/legacy_github_import/project_creator_spec.rb
+++ b/spec/lib/gitlab/legacy_github_import/project_creator_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe Gitlab::LegacyGithubImport::ProjectCreator do
before do
namespace.add_owner(user)
- expect_next_instance_of(Project) do |project|
+ allow_next_instances_of(Project, 2) do |project|
allow(project).to receive(:add_import_job)
end
end
diff --git a/spec/models/appearance_spec.rb b/spec/models/appearance_spec.rb
index 0a1de1d5dc4..b5f47c950b9 100644
--- a/spec/models/appearance_spec.rb
+++ b/spec/models/appearance_spec.rb
@@ -26,6 +26,7 @@ RSpec.describe Appearance do
it { expect(appearance.message_background_color).to eq('#E75E40') }
it { expect(appearance.message_font_color).to eq('#FFFFFF') }
it { expect(appearance.email_header_and_footer_enabled).to eq(false) }
+ it { expect(Appearance::ALLOWED_PWA_ICON_SCALER_WIDTHS).to match_array([192, 512]) }
end
describe '#single_appearance_row' do
@@ -84,6 +85,19 @@ RSpec.describe Appearance do
it_behaves_like 'logo paths', logo_type
end
+ shared_examples 'icon paths sized' do |width|
+ let_it_be(:appearance) { create(:appearance, :with_pwa_icon) }
+ let_it_be(:filename) { 'dk.png' }
+ let_it_be(:expected_path) { "/uploads/-/system/appearance/pwa_icon/#{appearance.id}/#{filename}?width=#{width}" }
+
+ it 'returns icon path with size parameter' do
+ expect(appearance.pwa_icon_path_scaled(width)).to eq(expected_path)
+ end
+ end
+
+ it_behaves_like 'icon paths sized', 192
+ it_behaves_like 'icon paths sized', 512
+
describe 'validations' do
let(:triplet) { '#000' }
let(:hex) { '#AABBCC' }
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 5888f9d109c..4a59f8d8efc 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -226,9 +226,9 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep, feature_category:
let_it_be(:pipeline2) { create(:ci_pipeline, name: 'Chatops pipeline') }
context 'when name exists' do
- let(:name) { 'build Pipeline' }
+ let(:name) { 'Build pipeline' }
- it 'performs case insensitive compare' do
+ it 'performs exact compare' do
is_expected.to contain_exactly(pipeline1)
end
end
diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb
index 451db9eaf9c..668b3aa8236 100644
--- a/spec/policies/group_policy_spec.rb
+++ b/spec/policies/group_policy_spec.rb
@@ -667,6 +667,42 @@ RSpec.describe GroupPolicy, feature_category: :authentication_and_authorization
it { is_expected.to be_allowed(:create_projects) }
end
+
+ context 'when there are no available visibility levels because they have been restricted by an administrator' do
+ before do
+ stub_application_setting(
+ restricted_visibility_levels: [
+ Gitlab::VisibilityLevel::PUBLIC,
+ Gitlab::VisibilityLevel::INTERNAL,
+ Gitlab::VisibilityLevel::PRIVATE
+ ]
+ )
+ end
+
+ context 'reporter' do
+ let(:current_user) { reporter }
+
+ it { is_expected.to be_disallowed(:create_projects) }
+ end
+
+ context 'developer' do
+ let(:current_user) { developer }
+
+ it { is_expected.to be_disallowed(:create_projects) }
+ end
+
+ context 'maintainer' do
+ let(:current_user) { maintainer }
+
+ it { is_expected.to be_disallowed(:create_projects) }
+ end
+
+ context 'owner' do
+ let(:current_user) { owner }
+
+ it { is_expected.to be_disallowed(:create_projects) }
+ end
+ end
end
end
diff --git a/spec/requests/api/draft_notes_spec.rb b/spec/requests/api/draft_notes_spec.rb
index cff8c34e4a1..b8331e072cf 100644
--- a/spec/requests/api/draft_notes_spec.rb
+++ b/spec/requests/api/draft_notes_spec.rb
@@ -9,8 +9,8 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do
let_it_be(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) }
let_it_be(:merge_request_note) { create(:note, noteable: merge_request, project: project, author: user) }
- let_it_be(:draft_note_by_current_user) { create(:draft_note, merge_request: merge_request, author: user) }
- let_it_be(:draft_note_by_random_user) { create(:draft_note, merge_request: merge_request) }
+ let!(:draft_note_by_current_user) { create(:draft_note, merge_request: merge_request, author: user) }
+ let!(:draft_note_by_random_user) { create(:draft_note, merge_request: merge_request) }
before do
project.add_developer(user)
@@ -74,4 +74,47 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do
end
end
end
+
+ describe "delete a draft note" do
+ context "when deleting an existing draft note by the user" do
+ let!(:deleted_draft_note_id) { draft_note_by_current_user.id }
+
+ before do
+ delete api(
+ "/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes/#{draft_note_by_current_user.id}",
+ user
+ )
+ end
+
+ it "returns 204 No Content status" do
+ expect(response).to have_gitlab_http_status(:no_content)
+ end
+
+ it "deletes the specified draft note" do
+ expect(DraftNote.exists?(deleted_draft_note_id)).to eq(false)
+ end
+ end
+
+ context "when deleting a non-existent draft note" do
+ it "returns a 404 Not Found" do
+ delete api(
+ "/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes/#{non_existing_record_id}",
+ user
+ )
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context "when deleting a draft note by a different user" do
+ it "returns a 404 Not Found" do
+ delete api(
+ "/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes/#{draft_note_by_random_user.id}",
+ user
+ )
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
end
diff --git a/spec/requests/pwa_controller_spec.rb b/spec/requests/pwa_controller_spec.rb
index 393f8803375..08eeefd1dc4 100644
--- a/spec/requests/pwa_controller_spec.rb
+++ b/spec/requests/pwa_controller_spec.rb
@@ -4,28 +4,74 @@ require 'spec_helper'
RSpec.describe PwaController, feature_category: :navigation do
describe 'GET #manifest' do
- it 'responds with json' do
- get manifest_path(format: :json)
+ shared_examples 'text values' do |params, result|
+ let_it_be(:appearance) { create(:appearance, **params) }
- expect(Gitlab::Json.parse(response.body)).to include({ 'name' => 'GitLab' })
- expect(Gitlab::Json.parse(response.body)).to include({ 'short_name' => 'GitLab' })
- expect(response.body).to include('The complete DevOps platform.')
- expect(response).to have_gitlab_http_status(:success)
+ it 'uses custom values', :aggregate_failures do
+ get manifest_path(format: :json)
+
+ expect(Gitlab::Json.parse(response.body)).to include(result)
+ expect(response).to have_gitlab_http_status(:success)
+ end
+ end
+
+ context 'with default appearance' do
+ it_behaves_like 'text values', {}, {
+ 'name' => 'GitLab',
+ 'short_name' => 'GitLab',
+ 'description' => 'The complete DevOps platform. ' \
+ 'One application with endless possibilities. ' \
+ 'Organizations rely on GitLab’s source code management, ' \
+ 'CI/CD, security, and more to deliver software rapidly.'
+ }
end
context 'with customized appearance' do
- let_it_be(:appearance) do
- create(:appearance, pwa_name: 'PWA name', pwa_short_name: 'Short name', pwa_description: 'This is a test')
+ context 'with custom text values' do
+ it_behaves_like 'text values', { pwa_name: 'PWA name' }, { 'name' => 'PWA name' }
+ it_behaves_like 'text values', { pwa_short_name: 'Short name' }, { 'short_name' => 'Short name' }
+ it_behaves_like 'text values', { pwa_description: 'This is a test' }, { 'description' => 'This is a test' }
end
- it 'uses custom values', :aggregate_failures do
- get manifest_path(format: :json)
+ shared_examples 'icon paths' do
+ it 'returns expected icon paths', :aggregate_failures do
+ get manifest_path(format: :json)
+
+ expect(Gitlab::Json.parse(response.body)["icons"]).to match_array(result)
+ expect(response).to have_gitlab_http_status(:success)
+ end
+ end
+
+ context 'with custom icon' do
+ let_it_be(:appearance) { create(:appearance, :with_pwa_icon) }
+ let_it_be(:result) do
+ [{ "src" => "/uploads/-/system/appearance/pwa_icon/#{appearance.id}/dk.png?width=192", "sizes" => "192x192",
+ "type" => "image/png" },
+ { "src" => "/uploads/-/system/appearance/pwa_icon/#{appearance.id}/dk.png?width=512", "sizes" => "512x512",
+ "type" => "image/png" }]
+ end
+
+ it_behaves_like 'icon paths'
+ end
- expect(Gitlab::Json.parse(response.body)).to include({
- 'description' => 'This is a test',
- 'name' => 'PWA name',
- 'short_name' => 'Short name'
- })
+ context 'with no custom icon' do
+ let_it_be(:appearance) { create(:appearance) }
+ let_it_be(:result) do
+ [{ "src" => "/-/pwa-icons/logo-192.png", "sizes" => "192x192", "type" => "image/png" },
+ { "src" => "/-/pwa-icons/logo-512.png", "sizes" => "512x512", "type" => "image/png" },
+ { "src" => "/-/pwa-icons/maskable-logo.png", "sizes" => "512x512", "type" => "image/png",
+ "purpose" => "maskable" }]
+ end
+
+ it_behaves_like 'icon paths'
+ end
+ end
+
+ describe 'GET #offline' do
+ it 'responds with static HTML page' do
+ get offline_path
+
+ expect(response.body).to include('You are currently offline')
expect(response).to have_gitlab_http_status(:success)
end
end
@@ -47,13 +93,4 @@ RSpec.describe PwaController, feature_category: :navigation do
end
end
end
-
- describe 'GET #offline' do
- it 'responds with static HTML page' do
- get offline_path
-
- expect(response.body).to include('You are currently offline')
- expect(response).to have_gitlab_http_status(:success)
- end
- end
end