提交 185d9acf 编写于 作者: G GitLab Bot

Add latest changes from gitlab-org/gitlab@master

上级 e65c1d31
......@@ -1033,8 +1033,6 @@ Rails/SaveBang:
- 'ee/spec/support/shared_examples/models/member_shared_examples.rb'
- 'ee/spec/support/shared_examples/models/mentionable_shared_examples.rb'
- 'ee/spec/support/shared_examples/policies/protected_environments_shared_examples.rb'
- 'ee/spec/support/shared_examples/services/build_execute_shared_examples.rb'
- 'ee/spec/support/shared_examples/services/issue_epic_shared_examples.rb'
- 'ee/spec/workers/adjourned_project_deletion_worker_spec.rb'
- 'ee/spec/workers/clear_shared_runners_minutes_worker_spec.rb'
- 'ee/spec/workers/create_github_webhook_worker_spec.rb'
......@@ -1488,9 +1486,6 @@ Rails/SaveBang:
- 'spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb'
- 'spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb'
- 'spec/support/shared_examples/serializers/note_entity_shared_examples.rb'
- 'spec/support/shared_examples/services/common_system_notes_shared_examples.rb'
- 'spec/support/shared_examples/services/issuable_shared_examples.rb'
- 'spec/support/shared_examples/services/wiki_pages/destroy_service_shared_examples.rb'
- 'spec/tasks/gitlab/web_hook_rake_spec.rb'
- 'spec/uploaders/file_uploader_spec.rb'
- 'spec/uploaders/object_storage_spec.rb'
......@@ -64,4 +64,4 @@ export const trackAlertStatusUpdateOptions = {
label: 'Status',
};
export const DEFAULT_PAGE_SIZE = 10;
export const DEFAULT_PAGE_SIZE = 20;
......@@ -34,4 +34,4 @@ export const INCIDENT_STATUS_TABS = [
];
export const INCIDENT_SEARCH_DELAY = 300;
export const DEFAULT_PAGE_SIZE = 10;
export const DEFAULT_PAGE_SIZE = 20;
......@@ -4,6 +4,7 @@ import { mapActions, mapState } from 'vuex';
import { GlLink, GlDeprecatedButton, GlIcon } from '@gitlab/ui';
import { __, sprintf } from '~/locale';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
import { timeIntervalInWords } from '~/lib/utils/datetime_utility';
import DetailRow from './sidebar_detail_row.vue';
import ArtifactsBlock from './artifacts_block.vue';
......@@ -24,6 +25,7 @@ export default {
JobsContainer,
GlLink,
GlDeprecatedButton,
TooltipOnTruncate,
},
mixins: [timeagoMixin],
props: {
......@@ -111,7 +113,11 @@ export default {
<div class="sidebar-container">
<div class="blocks-container">
<div class="block d-flex flex-nowrap align-items-center">
<h4 class="my-0 mr-2 text-break-word">{{ job.name }}</h4>
<tooltip-on-truncate :title="job.name" truncate-target="child"
><h4 class="my-0 mr-2 gl-text-truncate">
{{ job.name }}
</h4>
</tooltip-on-truncate>
<div class="flex-grow-1 flex-shrink-0 text-right">
<gl-link
v-if="job.retry_path"
......
......@@ -275,6 +275,81 @@ export const convertToSentenceCase = string => {
*/
export const convertToTitleCase = string => string.replace(/\b[a-z]/g, s => s.toUpperCase());
const unicodeConversion = [
[/[ÀÁÂÃÅĀĂĄ]/g, 'A'],
[/[Æ]/g, 'AE'],
[/[ÇĆĈĊČ]/g, 'C'],
[/[ÈÉÊËĒĔĖĘĚ]/g, 'E'],
[/[ÌÍÎÏĨĪĬĮİ]/g, 'I'],
[/[Ððĥħ]/g, 'h'],
[/[ÑŃŅŇʼn]/g, 'N'],
[/[ÒÓÔÕÖØŌŎŐ]/g, 'O'],
[/[ÙÚÛŨŪŬŮŰŲ]/g, 'U'],
[/[ÝŶŸ]/g, 'Y'],
[/[Þñþńņň]/g, 'n'],
[/[ߌŜŞŠ]/g, 'S'],
[/[àáâãåāăąĸ]/g, 'a'],
[/[æ]/g, 'ae'],
[/[çćĉċč]/g, 'c'],
[/[èéêëēĕėęě]/g, 'e'],
[/[ìíîïĩīĭį]/g, 'i'],
[/[òóôõöøōŏő]/g, 'o'],
[/[ùúûũūŭůűų]/g, 'u'],
[/[ýÿŷ]/g, 'y'],
[/[ĎĐ]/g, 'D'],
[/[ďđ]/g, 'd'],
[/[ĜĞĠĢ]/g, 'G'],
[/[ĝğġģŊŋſ]/g, 'g'],
[/[ĤĦ]/g, 'H'],
[/[ıśŝşš]/g, 's'],
[/[IJ]/g, 'IJ'],
[/[ij]/g, 'ij'],
[/[Ĵ]/g, 'J'],
[/[ĵ]/g, 'j'],
[/[Ķ]/g, 'K'],
[/[ķ]/g, 'k'],
[/[ĹĻĽĿŁ]/g, 'L'],
[/[ĺļľŀł]/g, 'l'],
[/[Œ]/g, 'OE'],
[/[œ]/g, 'oe'],
[/[ŔŖŘ]/g, 'R'],
[/[ŕŗř]/g, 'r'],
[/[ŢŤŦ]/g, 'T'],
[/[ţťŧ]/g, 't'],
[/[Ŵ]/g, 'W'],
[/[ŵ]/g, 'w'],
[/[ŹŻŽ]/g, 'Z'],
[/[źżž]/g, 'z'],
[/ö/g, 'oe'],
[/ü/g, 'ue'],
[/ä/g, 'ae'],
// eslint-disable-next-line @gitlab/require-i18n-strings
[/Ö/g, 'Oe'],
// eslint-disable-next-line @gitlab/require-i18n-strings
[/Ü/g, 'Ue'],
// eslint-disable-next-line @gitlab/require-i18n-strings
[/Ä/g, 'Ae'],
];
/**
* Converts each non-ascii character in a string to
* it's ascii equivalent (if defined).
*
* e.g. "Dĭd söméònê äšk fœŕ Ůnĭċődę?" => "Did someone aesk foer Unicode?"
*
* @param {String} string
* @returns {String}
*/
export const convertUnicodeToAscii = string => {
let convertedString = string;
unicodeConversion.forEach(([regex, replacer]) => {
convertedString = convertedString.replace(regex, replacer);
});
return convertedString;
};
/**
* Splits camelCase or PascalCase words
* e.g. HelloWorld => Hello World
......
import $ from 'jquery';
import DEFAULT_PROJECT_TEMPLATES from 'ee_else_ce/projects/default_project_templates';
import { addSelectOnFocusBehaviour } from '../lib/utils/common_utils';
import { convertToTitleCase, humanize, slugify } from '../lib/utils/text_utility';
import {
convertToTitleCase,
humanize,
slugify,
convertUnicodeToAscii,
} from '../lib/utils/text_utility';
let hasUserDefinedProjectPath = false;
let hasUserDefinedProjectName = false;
const onProjectNameChange = ($projectNameInput, $projectPathInput) => {
const slug = slugify($projectNameInput.val());
const slug = slugify(convertUnicodeToAscii($projectNameInput.val()));
$projectPathInput.val(slug);
};
......
......@@ -61,9 +61,9 @@ export default {
v-tooltip
:title="title"
:data-placement="placement"
class="js-show-tooltip"
class="js-show-tooltip gl-min-w-0"
>
<slot></slot>
</span>
<span v-else> <slot></slot> </span>
<span v-else class="gl-min-w-0"> <slot></slot> </span>
</template>
---
title: Truncate job title on log page
merge_request: 40107
author:
type: changed
---
title: Increase default page size for Alert and Incident management to 20 from 10
merge_request: 40139
author:
type: changed
---
title: Replace Unicode Characters with ASCII Equivalent in New Project Slug
merge_request: 39971
author: Kev @KevSlashNull
type: changed
---
title: Refactor spec/support/shared_examples/services/* and ee/spec/support/shared_examples/services/* to fix Rails/SaveBang Cop
merge_request: 39538
author: Rajendra Kadam
type: fixed
......@@ -321,80 +321,56 @@ it('tests a promise', async () => {
});
it('tests a promise rejection', async () => {
expect.assertions(1);
try {
await user.getUserName(1);
} catch (e) {
expect(e).toEqual({
error: 'User with 1 not found.',
});
}
await expect(user.getUserName(1)).rejects.toThrow('User with 1 not found.');
});
```
You can also work with Promise chains. In this case, you can make use of the `done` callback and `done.fail` in case an error occurred. Following are some examples:
You can also simply return a promise from the test function.
NOTE: **Note:**
Using the `done` and `done.fail` callbacks is discouraged when working with
promises. They should only be used when testing callback-based code.
**Bad**:
```javascript
// missing done callback
// missing return
it('tests a promise', () => {
promise.then(data => {
expect(data).toBe(asExpected);
});
});
// missing catch
it('tests a promise', done => {
promise
.then(data => {
expect(data).toBe(asExpected);
})
.then(done);
});
// use done.fail in asynchronous tests
// uses done/done.fail
it('tests a promise', done => {
promise
.then(data => {
expect(data).toBe(asExpected);
})
.then(done)
.catch(fail);
});
// missing catch
it('tests a promise rejection', done => {
promise
.catch(error => {
expect(error).toBe(expectedError);
})
.then(done);
.catch(done.fail);
});
```
**Good**:
```javascript
// handling success
it('tests a promise', done => {
promise
// verifying a resolved promise
it('tests a promise', () => {
return promise
.then(data => {
expect(data).toBe(asExpected);
})
.then(done)
.catch(done.fail);
});
});
// failure case
it('tests a promise rejection', done => {
promise
.then(done.fail)
.catch(error => {
expect(error).toBe(expectedError);
})
.then(done)
.catch(done.fail);
// verifying a resolved promise using Jest's `resolves` matcher
it('tests a promise', () => {
return expect(promise).resolves.toBe(asExpected);
});
// verifying a rejected promise using Jest's `rejects` matcher
it('tests a promise rejection', () => {
return expect(promise).rejects.toThrow(expectedError);
});
```
......
......@@ -35,13 +35,15 @@ module QA
private
def format_example(example)
file_path, line_number = location_including_shared_examples(example.metadata)
{
id: example.id,
description: example.description,
full_description: example.full_description,
status: example.execution_result.status.to_s,
file_path: example.metadata[:file_path],
line_number: example.metadata[:line_number],
file_path: file_path,
line_number: line_number.to_i,
run_time: example.execution_result.run_time,
pending_message: example.execution_result.pending_message,
status_issue: example.metadata[:status_issue],
......@@ -49,6 +51,15 @@ module QA
screenshot: example.metadata[:screenshot]
}
end
def location_including_shared_examples(metadata)
if metadata[:shared_group_inclusion_backtrace].empty?
[metadata[:file_path], metadata[:line_number]]
else
# If there are nested shared examples, the outermost location is last in the array
metadata[:shared_group_inclusion_backtrace].last.formatted_inclusion_location.split(':')
end
end
end
end
end
......@@ -49,11 +49,11 @@ describe('AlertManagementTable', () => {
const findIssueFields = () => wrapper.findAll('[data-testid="issueField"]');
const findAlertError = () => wrapper.find('[data-testid="alert-error"]');
const alertsCount = {
open: 14,
triggered: 10,
acknowledged: 6,
resolved: 1,
all: 16,
open: 24,
triggered: 20,
acknowledged: 16,
resolved: 11,
all: 26,
};
const selectFirstStatusOption = () => {
findFirstStatusOption().vm.$emit('click');
......
......@@ -30,9 +30,9 @@ describe('Incidents List', () => {
const incidentTemplateName = 'incident';
const incidentType = 'incident';
const incidentsCount = {
opened: 14,
closed: 1,
all: 16,
opened: 24,
closed: 10,
all: 26,
};
const findTable = () => wrapper.find(GlTable);
......
......@@ -205,6 +205,26 @@ describe('text_utility', () => {
});
});
describe('convertUnicodeToAscii', () => {
it('does nothing on an empty string', () => {
expect(textUtils.convertUnicodeToAscii('')).toBe('');
});
it('does nothing on an already ascii string', () => {
expect(textUtils.convertUnicodeToAscii('The quick brown fox jumps over the lazy dog.')).toBe(
'The quick brown fox jumps over the lazy dog.',
);
});
it('replaces Unicode characters', () => {
expect(textUtils.convertUnicodeToAscii('Dĭd söméònê äšk fœŕ Ůnĭċődę?')).toBe(
'Did someone aesk foer Unicode?',
);
expect(textUtils.convertUnicodeToAscii("Jürgen's Projekt")).toBe("Juergen's Projekt");
});
});
describe('splitCamelCase', () => {
it('separates a PascalCase word to two', () => {
expect(textUtils.splitCamelCase('HelloWorld')).toBe('Hello World');
......
......@@ -5,7 +5,7 @@ RSpec.shared_examples 'system note creation' do |update_params, note_text|
before do
issuable.assign_attributes(update_params)
issuable.save
issuable.save!
end
it 'creates 1 system note with the correct content' do
......
......@@ -19,7 +19,7 @@ RSpec.shared_examples 'system notes for milestones' do
let(:group_milestone) { create(:milestone, group: group) }
before do
project.update(namespace: group)
project.update!(namespace: group)
create(:group_member, group: group, user: user)
end
......
# frozen_string_literal: true
RSpec.shared_examples 'WikiPages::DestroyService#execute' do |container_type|
let(:container) { create(container_type) }
let(:container) { create(container_type) } # rubocop:disable Rails/SaveBang
let(:user) { create(:user) }
let(:page) { create(:wiki_page) }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册