Commit 581f10ee authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-04-12

parents b90be12d b9d868e3
......@@ -467,12 +467,12 @@ update-tests-metadata:
- rspec_flaky/
policy: push
script:
- retry gem install fog-aws mime-types
- retry gem install fog-aws mime-types activesupport
- scripts/merge-reports ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec-pg_node_*.json
- scripts/merge-reports ${KNAPSACK_SPINACH_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/spinach-pg_node_*.json
- scripts/merge-reports ${EE_KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec-pg-ee_node_*.json
- scripts/merge-reports ${FLAKY_RSPEC_SUITE_REPORT_PATH} rspec_flaky/all_*_*.json
- scripts/prune-old-flaky-specs ${FLAKY_RSPEC_SUITE_REPORT_PATH}
- FLAKY_RSPEC_GENERATE_REPORT=1 scripts/prune-old-flaky-specs ${FLAKY_RSPEC_SUITE_REPORT_PATH}
- '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $KNAPSACK_RSPEC_SUITE_REPORT_PATH $KNAPSACK_SPINACH_SUITE_REPORT_PATH'
- '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $EE_KNAPSACK_RSPEC_SUITE_REPORT_PATH'
- '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $FLAKY_RSPEC_SUITE_REPORT_PATH'
......
......@@ -5,7 +5,7 @@ import AccessorUtilities from '~/lib/utils/accessor';
* Does that setting the current selected tab in the localStorage
*/
export default class SigninTabsMemoizer {
constructor({ currentTabKey = 'current_signin_tab', tabSelector = 'ul.nav-tabs' } = {}) {
constructor({ currentTabKey = 'current_signin_tab', tabSelector = 'ul.new-session-tabs' } = {}) {
this.currentTabKey = currentTabKey;
this.tabSelector = tabSelector;
this.isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();
......
<script>
export default {
name: 'time-tracking-estimate-only-pane',
name: 'TimeTrackingEstimateOnlyPane',
props: {
timeEstimateHumanReadable: {
type: String,
required: true,
},
},
template: `
<div class="time-tracking-estimate-only-pane">
<span class="bold">
{{ s__('TimeTracking|Estimated:') }}
</span>
{{ timeEstimateHumanReadable }}
</div>
`,
};
</script>
<template>
<div class="time-tracking-estimate-only-pane">
<span class="bold">
{{ s__('TimeTracking|Estimated:') }}
</span>
{{ timeEstimateHumanReadable }}
</div>
</template>
......@@ -3,7 +3,7 @@ import timeTrackingHelpState from './help_state';
import TimeTrackingCollapsedState from './collapsed_state.vue';
import timeTrackingSpentOnlyPane from './spent_only_pane';
import timeTrackingNoTrackingPane from './no_tracking_pane';
import timeTrackingEstimateOnlyPane from './estimate_only_pane';
import TimeTrackingEstimateOnlyPane from './estimate_only_pane.vue';
import TimeTrackingComparisonPane from './comparison_pane.vue';
import eventHub from '../../event_hub';
......@@ -12,7 +12,7 @@ export default {
name: 'IssuableTimeTracker',
components: {
TimeTrackingCollapsedState,
'time-tracking-estimate-only-pane': timeTrackingEstimateOnlyPane,
TimeTrackingEstimateOnlyPane,
'time-tracking-spent-only-pane': timeTrackingSpentOnlyPane,
'time-tracking-no-tracking-pane': timeTrackingNoTrackingPane,
TimeTrackingComparisonPane,
......
......@@ -7,7 +7,10 @@ export default {
statusIcon,
},
props: {
mr: { type: Object, required: true },
mr: {
type: Object,
required: true,
},
},
};
</script>
......@@ -20,13 +23,14 @@ export default {
/>
<div class="media-body space-children">
<span class="bold">
There are unresolved discussions. Please resolve these discussions
{{ s__("mrWidget|There are unresolved discussions. Please resolve these discussions") }}
</span>
<a
v-if="mr.createIssueToResolveDiscussionsPath"
:href="mr.createIssueToResolveDiscussionsPath"
class="btn btn-default btn-xs js-create-issue">
Create an issue to resolve them later
class="btn btn-default btn-xs js-create-issue"
>
{{ s__("mrWidget|Create an issue to resolve them later") }}
</a>
</div>
</div>
......
......@@ -154,26 +154,10 @@
a {
width: 100%;
font-size: 18px;
margin-right: 0;
&:hover {
border: 1px solid transparent;
}
}
&.active {
border-bottom: 1px solid $border-color;
a {
border: 0;
border-bottom: 2px solid $link-underline-blue;
margin-right: 0;
color: $black;
&:hover {
border-bottom: 2px solid $link-underline-blue;
}
}
&.active > a {
cursor: default;
}
}
}
......
%ul.nav-links.nav-tabs.new-session-tabs.single-tab
%ul.nav-links.new-session-tabs.single-tab
%li.active
%a= tab_title
%ul.new-session-tabs.nav-links.nav-tabs{ class: ('custom-provider-tabs' if form_based_providers.any?) }
%ul.nav-links.new-session-tabs{ class: ('custom-provider-tabs' if form_based_providers.any?) }
- if crowd_enabled?
%li.active
= link_to "Crowd", "#crowd", 'data-toggle' => 'tab'
......
%ul.nav-links.new-session-tabs.nav-tabs{ role: 'tablist' }
%ul.nav-links.new-session-tabs{ role: 'tablist' }
%li.active{ role: 'presentation' }
%a{ href: '#login-pane', data: { toggle: 'tab' }, role: 'tab' } Sign in
- if allow_signup?
......
......@@ -57,7 +57,7 @@
- else
Job has been erased #{time_ago_with_tooltip(@build.erased_at)}
- if @build.has_trace?
- if @build.running? || @build.has_trace?
.build-trace-container.prepend-top-default
.top-bar.js-top-bar
.js-truncated-info.truncated-info.hidden-xs.pull-left.hidden<
......
---
title: Refactor CSS to eliminate vertical misalignment of login nav
merge_request: 16275
author: Takuya Noguchi
type: fixed
---
title: Fix finding wiki file when Gitaly is enabled
merge_request:
author:
type: fixed
---
title: Move TimeTrackingEstimateOnlyPane vue component
merge_request: 18318
author: George Tsiolis
type: performance
---
title: Add i18n and update specs for UnresolvedDiscussions vue component
merge_request: 17866
author: George Tsiolis
type: performance
var path = require('path');
var webpack = require('webpack');
var argumentsParser = require('commander');
var webpackConfig = require('./webpack.config.js');
var ROOT_PATH = path.resolve(__dirname, '..');
......@@ -14,6 +15,24 @@ if (webpackConfig.plugins) {
});
}
var testFiles = argumentsParser
.option(
'-f, --filter-spec [filter]',
'Filter run spec files by path. Multiple filters are like a logical OR.',
(val, memo) => {
memo.push(val);
return memo;
},
[]
)
.parse(process.argv).filterSpec;
webpackConfig.plugins.push(
new webpack.DefinePlugin({
'process.env.TEST_FILES': JSON.stringify(testFiles),
})
);
webpackConfig.devtool = 'cheap-inline-source-map';
// Karma configuration
......
......@@ -131,6 +131,9 @@ There is also and alternative method to [translate messages from validation erro
### Interpolation
Placeholders in translated text should match the code style of the respective source file.
For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript.
- In Ruby/HAML:
```ruby
......@@ -141,11 +144,19 @@ There is also and alternative method to [translate messages from validation erro
```js
import { __, sprintf } from '~/locale';
sprintf(__('Hello %{username}'), { username: 'Joe' }) => 'Hello Joe'
sprintf(__('Hello %{username}'), { username: 'Joe' }); // => 'Hello Joe'
```
The placeholders should match the code style of the respective source file.
For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript.
By default, `sprintf` escapes the placeholder values.
If you want to take care of that yourself, you can pass `false` as third argument.
```js
import { __, sprintf } from '~/locale';
sprintf(__('This is %{value}'), { value: '<strong>bold</strong>' }); // => 'This is &lt;strong&gt;bold&lt;/strong&gt;'
sprintf(__('This is %{value}'), { value: '<strong>bold</strong>' }, false); // => 'This is <strong>bold</strong>'
```
### Plurals
......
......@@ -152,19 +152,33 @@ is sufficient (and saves you some time).
### Live testing and focused testing
While developing locally, it may be helpful to keep karma running so that you
can get instant feedback on as you write tests and modify code. To do this
you can start karma with `npm run karma-start`. It will compile the javascript
can get instant feedback on as you write tests and modify code. To do this
you can start karma with `yarn run karma-start`. It will compile the javascript
assets and run a server at `http://localhost:9876/` where it will automatically
run the tests on any browser which connects to it. You can enter that url on
run the tests on any browser which connects to it. You can enter that url on
multiple browsers at once to have it run the tests on each in parallel.
While karma is running, any changes you make will instantly trigger a recompile
and retest of the entire test suite, so you can see instantly if you've broken
a test with your changes. You can use [jasmine focused][jasmine-focus] or
a test with your changes. You can use [jasmine focused][jasmine-focus] or
excluded tests (with `fdescribe` or `xdescribe`) to get karma to run only the
tests you want while you're working on a specific feature, but make sure to
remove these directives when you commit your code.
It is also possible to only run karma on specific folders or files by filtering
the run tests via the argument `--filter-spec` or short `-f`:
```bash
# Run all files
yarn karma-start
# Run specific spec files
yarn karma-start --filter-spec profile/account/components/update_username_spec.js
# Run specific spec folder
yarn karma-start --filter-spec profile/account/components/
# Run all specs which path contain vue_shared or vie
yarn karma-start -f vue_shared -f vue_mr_widget
```
## RSpec feature integration tests
Information on setting up and running RSpec integration tests with
......@@ -176,7 +190,7 @@ Information on setting up and running RSpec integration tests with
Similar errors will be thrown if you're using JavaScript features not yet
supported by the PhantomJS test runner which is used for both Karma and RSpec
tests. We polyfill some JavaScript objects for older browsers, but some
tests. We polyfill some JavaScript objects for older browsers, but some
features are still unavailable:
- Array.from
......@@ -188,7 +202,7 @@ features are still unavailable:
- Symbol/Symbol.iterator
- Spread
Until these are polyfilled appropriately, they should not be used. Please
Until these are polyfilled appropriately, they should not be used. Please
update this list with additional unsupported features.
### RSpec errors due to JavaScript
......@@ -223,7 +237,7 @@ end
### Spinach errors due to missing JavaScript
NOTE: **Note:** Since we are discouraging the use of Spinach when writing new
feature tests, you shouldn't ever need to use this. This information is kept
feature tests, you shouldn't ever need to use this. This information is kept
available for legacy purposes only.
In Spinach, the JavaScript driver is enabled differently. In the `*.feature`
......
......@@ -3,6 +3,14 @@ module Gitlab
module Status
module Build
module Common
def illustration
{
image: 'illustrations/skipped-job_empty.svg',
size: 'svg-430',
title: _('This job does not have a trace.')
}
end
def has_details?
can?(user, :read_build, subject)
end
......
......@@ -136,7 +136,7 @@ module Gitlab
wiki_file = nil
response.each do |message|
next unless message.name.present?
next unless message.name.present? || wiki_file
if wiki_file
wiki_file.raw_data << message.raw_data
......
......@@ -5,8 +5,8 @@
"eslint": "eslint --max-warnings 0 --ext .js,.vue .",
"eslint-fix": "eslint --max-warnings 0 --ext .js,.vue --fix .",
"eslint-report": "eslint --max-warnings 0 --ext .js,.vue --format html --output-file ./eslint-report.html .",
"karma": "karma start config/karma.config.js --single-run",
"karma-coverage": "BABEL_ENV=coverage karma start config/karma.config.js --single-run",
"karma": "karma start --single-run true config/karma.config.js",
"karma-coverage": "BABEL_ENV=coverage karma start --single-run true config/karma.config.js",
"karma-start": "karma start config/karma.config.js",
"prettier-staged": "node ./scripts/frontend/prettier.js",
"prettier-staged-save": "node ./scripts/frontend/prettier.js save",
......@@ -100,6 +100,7 @@
"axios-mock-adapter": "^1.10.0",
"babel-eslint": "^8.0.2",
"babel-plugin-istanbul": "^4.1.5",
"commander": "^2.15.1",
"eslint": "^3.18.0",
"eslint-config-airbnb-base": "^10.0.1",
"eslint-import-resolver-webpack": "^0.8.3",
......
#!/usr/bin/env ruby
# lib/rspec_flaky/flaky_examples_collection.rb is requiring
# `active_support/hash_with_indifferent_access`, and we install the `activesupport`
# gem manually on the CI
require 'rubygems'
require_relative '../lib/rspec_flaky/report'
report_file = ARGV.shift
......
......@@ -475,6 +475,17 @@ feature 'Jobs' do
expect(page).to have_content('This job has been skipped')
end
end
context 'when job is failed but has no trace' do
let(:job) { create(:ci_build, :failed, pipeline: pipeline) }
it 'renders empty state' do
visit project_job_path(project, job)
expect(job).not_to have_trace
expect(page).to have_content('This job does not have a trace.')
end
end
end
describe "POST /:project/jobs/:id/cancel", :js do
......
......@@ -406,7 +406,7 @@ feature 'Login' do
end
def ensure_one_active_tab
expect(page).to have_selector('.nav-tabs > li.active', count: 1)
expect(page).to have_selector('ul.new-session-tabs > li.active', count: 1)
end
def ensure_one_active_pane
......
%ul.nav.nav-tabs.linked-tabs
%ul.nav-links.new-session-tabs.linked-tabs
%li
%a{ href: 'foo/bar/1', data: { target: 'div#tab1', action: 'tab1', toggle: 'tab' } }
Tab 1
......
%ul.nav-tabs
%ul.nav-links.new-session-tabs
%li.active
%a{ href: '#ldap' } LDAP
%li
%a.active{ id: 'standard', href: '#standard'} Standard
%li
%a{ id: 'ldap', href: '#ldap'} Ldap
%a{ href: '#login-pane'} Standard
......@@ -4,7 +4,7 @@ import SigninTabsMemoizer from '~/pages/sessions/new/signin_tabs_memoizer';
(() => {
describe('SigninTabsMemoizer', () => {
const fixtureTemplate = 'static/signin_tabs.html.raw';
const tabSelector = 'ul.nav-tabs';
const tabSelector = 'ul.new-session-tabs';
const currentTabKey = 'current_signin_tab';
let memo;
......@@ -27,7 +27,7 @@ import SigninTabsMemoizer from '~/pages/sessions/new/signin_tabs_memoizer';
it('does nothing if no tab was previously selected', () => {
createMemoizer();
expect(document.querySelector('li a.active').getAttribute('id')).toEqual('standard');
expect(document.querySelector(`${tabSelector} > li.active a`).getAttribute('href')).toEqual('#ldap');
});
it('shows last selected tab on boot', () => {
......@@ -48,9 +48,9 @@ import SigninTabsMemoizer from '~/pages/sessions/new/signin_tabs_memoizer';
it('saves last selected tab on change', () => {
createMemoizer();
document.getElementById('standard').click();
document.querySelector('a[href="#login-pane"]').click();
expect(memo.readData()).toEqual('#standard');
expect(memo.readData()).toEqual('#login-pane');
});
it('overrides last selected tab with hash tag when given', () => {
......
......@@ -4,6 +4,7 @@ import 'vendor/jasmine-jquery';
import '~/commons';
import Vue from 'vue';
import VueResource from 'vue-resource';
import Translate from '~/vue_shared/translate';
import { getDefaultAdapter } from '~/lib/utils/axios_utils';
import { FIXTURES_PATH, TEST_HOST } from './test_constants';
......@@ -27,6 +28,7 @@ Vue.config.errorHandler = function(err) {
};
Vue.use(VueResource);
Vue.use(Translate);
// enable test fixtures
jasmine.getFixtures().fixturesPath = FIXTURES_PATH;
......@@ -69,11 +71,21 @@ beforeEach(() => {
const axiosDefaultAdapter = getDefaultAdapter();
let testFiles = process.env.TEST_FILES || [];
if (testFiles.length > 0) {
testFiles = testFiles.map(path => path.replace(/^spec\/javascripts\//, '').replace(/\.js$/, ''));
console.log(`Running only tests matching: ${testFiles}`);
} else {
console.log('Running all tests');
}
// render all of our tests
const testsContext = require.context('.', true, /_spec$/);
testsContext.keys().forEach(function(path) {
try {
testsContext(path);
if (testFiles.length === 0 || testFiles.some(p => path.includes(p))) {
testsContext(path);
}
} catch (err) {
console.error('[ERROR] Unable to load spec: ', path);
describe('Test bundle', function() {
......
import Vue from 'vue';
import UnresolvedDiscussions from '~/vue_merge_request_widget/components/states/unresolved_discussions.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('UnresolvedDiscussions', () => {
describe('props', () => {
it('should have props', () => {
const { mr } = UnresolvedDiscussions.props;
const Component = Vue.extend(UnresolvedDiscussions);
let vm;
expect(mr.type instanceof Object).toBeTruthy();
expect(mr.required).toBeTruthy();
});
afterEach(() => {
vm.$destroy();
});
describe('template', () => {
let el;
let vm;
const path = 'foo/bar';
describe('with discussions path', () => {
beforeEach(() => {
const Component = Vue.extend(UnresolvedDiscussions);
const mr = {
createIssueToResolveDiscussionsPath: path,
};
vm = new Component({
el: document.createElement('div'),
propsData: { mr },
});
el = vm.$el;
vm = mountComponent(Component, { mr: {
createIssueToResolveDiscussionsPath: gl.TEST_HOST,
} });
});
it('should have correct elements', () => {
expect(el.classList.contains('mr-widget-body')).toBeTruthy();
expect(el.innerText).toContain('There are unresolved discussions. Please resolve these discussions');
expect(el.innerText).toContain('Create an issue to resolve them later');
expect(el.querySelector('.js-create-issue').getAttribute('href')).toEqual(path);
expect(vm.$el.innerText).toContain('There are unresolved discussions. Please resolve these discussions');
expect(vm.$el.innerText).toContain('Create an issue to resolve them later');
expect(vm.$el.querySelector('.js-create-issue').getAttribute('href')).toEqual(gl.TEST_HOST);
});
});
it('should not show create issue button if user cannot create issue', (done) => {
vm.mr.createIssueToResolveDiscussionsPath = '';
describe('without discussions path', () => {
beforeEach(() => {
vm = mountComponent(Component, { mr: {} });
});
Vue.nextTick(() => {
expect(el.querySelector('.js-create-issue')).toEqual(null);
done();
});
it('should not show create issue link if user cannot create issue', () => {
expect(vm.$el.innerText).toContain('There are unresolved discussions. Please resolve these discussions');
expect(vm.$el.querySelector('.js-create-issue')).toEqual(null);
});
});
});
......@@ -38,4 +38,10 @@ describe Gitlab::Ci::Status::Build::Common do
expect(subject.details_path).to include "jobs/#{build.id}"
end
end
describe '#illustration' do
it 'provides a fallback empty state illustration' do
expect(subject.illustration).not_to be_empty
end
end
end
......@@ -75,7 +75,8 @@ describe Gitlab::Ci::Status::Build::Factory do
it 'matches correct extended statuses' do
expect(factory.extended_statuses)
.to eq [Gitlab::Ci::Status::Build::Retryable, Gitlab::Ci::Status::Build::Failed]
.to eq [Gitlab::Ci::Status::Build::Retryable,
Gitlab::Ci::Status::Build::Failed]
end
it 'fabricates a failed build status' do
......@@ -94,7 +95,7 @@ describe Gitlab::Ci::Status::Build::Factory do
end
context 'when build is allowed to fail' do
let(:build) { create(:ci_build, :failed, :allowed_to_fail) }
let(:build) { create(:ci_build, :failed, :allowed_to_fail, :trace_artifact) }
it 'matches correct core status' do
expect(factory.core_status).to be_a Gitlab::Ci::Status::Failed
......
......@@ -180,11 +180,12 @@ describe ProjectWiki do
describe '#find_file' do
shared_examples 'finding a wiki file' do
let(:image) { File.open(Rails.root.join('spec', 'fixtures', 'big-image.png')) }
before do
file = File.open(Rails.root.join('spec', 'fixtures', 'dk.png'))
subject.wiki # Make sure the wiki repo exists
BareRepoOperations.new(subject.repository.path_to_repo).commit_file(file, 'image.png')
BareRepoOperations.new(subject.repository.path_to_repo).commit_file(image, 'image.png')
end
it 'returns the latest version of the file if it exists' do
......@@ -200,6 +201,13 @@ describe ProjectWiki do
file = subject.find_file('image.png')
expect(file).to be_a Gitlab::Git::WikiFile
end
it 'returns the whole file' do
file = subject.find_file('image.png')
image.rewind
expect(file.raw_data.b).to eq(image.read.b)
end
end
context 'when Gitaly wiki_find_file is enabled' do
......
......@@ -1859,9 +1859,9 @@ combined-stream@1.0.6, combined-stream@^1.0.5, combined-stream@~1.0.5:
dependencies:
delayed-stream "~1.0.0"
commander@^2.13.0, commander@^2.9.0:
version "2.14.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa"
commander@^2.13.0, commander@^2.15.1, commander@^2.9.0:
version "2.15.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
commondir@^1.0.1:
version "1.0.1"
......
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