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
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-12-20 21:07:53 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2019-12-20 21:07:53 +0300
commit682360490629376e2ec07d737c7d7dbfdaaeeab7 (patch)
tree7abe62a4d200738ac086ac0c0bd633ce0bc03f00
parent2f26f81ce3e3f97ddc5ce5e2e103925d7d0d170f (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/ide/stores/actions.js36
-rw-r--r--app/assets/javascripts/ide/stores/actions/file.js22
-rw-r--r--app/assets/javascripts/ide/stores/getters.js1
-rw-r--r--app/assets/javascripts/ide/stores/mutations/file.js34
-rw-r--r--changelogs/unreleased/39498-part-3.yml5
-rw-r--r--changelogs/unreleased/dast_mr_reports_feature_flag.yml5
-rw-r--r--doc/api/issue_links.md8
-rw-r--r--doc/user/packages/index.md6
-rw-r--r--doc/user/packages/workflows/project_registry.md85
-rw-r--r--spec/frontend/__mocks__/@gitlab/ui.js19
-rw-r--r--spec/frontend/boards/issue_card_spec.js8
-rw-r--r--spec/frontend/diffs/components/compare_versions_spec.js2
-rw-r--r--spec/frontend/diffs/components/diff_file_header_spec.js2
-rw-r--r--spec/frontend/environments/environment_monitoring_spec.js2
-rw-r--r--spec/frontend/environments/environment_stop_spec.js2
-rw-r--r--spec/frontend/environments/environment_terminal_button_spec.js2
-rw-r--r--spec/frontend/ide/stores/actions/file_spec.js52
-rw-r--r--spec/frontend/ide/stores/mutations/file_spec.js174
-rw-r--r--spec/frontend/issuable_suggestions/components/item_spec.js2
-rw-r--r--spec/frontend/issuables_list/components/issuable_spec.js4
-rw-r--r--spec/frontend/notes/components/__snapshots__/discussion_jump_to_next_button_spec.js.snap3
-rw-r--r--spec/frontend/pipelines/graph/action_component_spec.js4
-rw-r--r--spec/frontend/pipelines/graph/job_item_spec.js12
-rw-r--r--spec/frontend/pipelines/graph/linked_pipeline_spec.js2
-rw-r--r--spec/frontend/pipelines/pipeline_url_spec.js4
-rw-r--r--spec/frontend/registry/list/components/__snapshots__/project_empty_state_spec.js.snap9
-rw-r--r--spec/frontend/releases/list/components/evidence_block_spec.js6
-rw-r--r--spec/frontend/releases/list/components/release_block_milestone_info_spec.js2
-rw-r--r--spec/frontend/releases/list/components/release_block_spec.js2
-rw-r--r--spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap6
-rw-r--r--spec/frontend/sidebar/assignees_spec.js2
-rw-r--r--spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js2
-rw-r--r--spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/changed_file_icon_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/clipboard_button_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/commit_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/issue/issue_assignees_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/time_ago_tooltip_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js6
-rw-r--r--spec/javascripts/ide/stores/actions_spec.js155
41 files changed, 485 insertions, 219 deletions
diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js
index 7a386299eed..66a89582da3 100644
--- a/app/assets/javascripts/ide/stores/actions.js
+++ b/app/assets/javascripts/ide/stores/actions.js
@@ -134,28 +134,40 @@ export const scrollToTab = () => {
});
};
-export const stageAllChanges = ({ state, commit, dispatch }) => {
+export const stageAllChanges = ({ state, commit, dispatch, getters }) => {
const openFile = state.openFiles[0];
commit(types.SET_LAST_COMMIT_MSG, '');
- state.changedFiles.forEach(file => commit(types.STAGE_CHANGE, file.path));
+ state.changedFiles.forEach(file =>
+ commit(types.STAGE_CHANGE, { path: file.path, diffInfo: getters.getDiffInfo(file.path) }),
+ );
- dispatch('openPendingTab', {
- file: state.stagedFiles.find(f => f.path === openFile.path),
- keyPrefix: stageKeys.staged,
- });
+ const file = getters.getStagedFile(openFile.path);
+
+ if (file) {
+ dispatch('openPendingTab', {
+ file,
+ keyPrefix: stageKeys.staged,
+ });
+ }
};
-export const unstageAllChanges = ({ state, commit, dispatch }) => {
+export const unstageAllChanges = ({ state, commit, dispatch, getters }) => {
const openFile = state.openFiles[0];
- state.stagedFiles.forEach(file => commit(types.UNSTAGE_CHANGE, file.path));
+ state.stagedFiles.forEach(file =>
+ commit(types.UNSTAGE_CHANGE, { path: file.path, diffInfo: getters.getDiffInfo(file.path) }),
+ );
- dispatch('openPendingTab', {
- file: state.changedFiles.find(f => f.path === openFile.path),
- keyPrefix: stageKeys.unstaged,
- });
+ const file = getters.getChangedFile(openFile.path);
+
+ if (file) {
+ dispatch('openPendingTab', {
+ file,
+ keyPrefix: stageKeys.unstaged,
+ });
+ }
};
export const updateViewer = ({ commit }, viewer) => {
diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js
index 8864224c19e..27b8e32bf5e 100644
--- a/app/assets/javascripts/ide/stores/actions/file.js
+++ b/app/assets/javascripts/ide/stores/actions/file.js
@@ -214,20 +214,20 @@ export const discardFileChanges = ({ dispatch, state, commit, getters }, path) =
eventHub.$emit(`editor.update.model.dispose.unstaged-${file.key}`, file.content);
};
-export const stageChange = ({ commit, state, dispatch }, path) => {
- const stagedFile = state.stagedFiles.find(f => f.path === path);
- const openFile = state.openFiles.find(f => f.path === path);
+export const stageChange = ({ commit, dispatch, getters }, path) => {
+ const stagedFile = getters.getStagedFile(path);
+ const openFile = getters.getOpenFile(path);
- commit(types.STAGE_CHANGE, path);
+ commit(types.STAGE_CHANGE, { path, diffInfo: getters.getDiffInfo(path) });
commit(types.SET_LAST_COMMIT_MSG, '');
if (stagedFile) {
eventHub.$emit(`editor.update.model.new.content.staged-${stagedFile.key}`, stagedFile.content);
}
- if (openFile && openFile.active) {
- const file = state.stagedFiles.find(f => f.path === path);
+ const file = getters.getStagedFile(path);
+ if (openFile && openFile.active && file) {
dispatch('openPendingTab', {
file,
keyPrefix: stageKeys.staged,
@@ -235,14 +235,14 @@ export const stageChange = ({ commit, state, dispatch }, path) => {
}
};
-export const unstageChange = ({ commit, dispatch, state }, path) => {
- const openFile = state.openFiles.find(f => f.path === path);
+export const unstageChange = ({ commit, dispatch, getters }, path) => {
+ const openFile = getters.getOpenFile(path);
- commit(types.UNSTAGE_CHANGE, path);
+ commit(types.UNSTAGE_CHANGE, { path, diffInfo: getters.getDiffInfo(path) });
- if (openFile && openFile.active) {
- const file = state.changedFiles.find(f => f.path === path);
+ const file = getters.getChangedFile(path);
+ if (openFile && openFile.active && file) {
dispatch('openPendingTab', {
file,
keyPrefix: stageKeys.unstaged,
diff --git a/app/assets/javascripts/ide/stores/getters.js b/app/assets/javascripts/ide/stores/getters.js
index bb8374b4e78..2fc574cd343 100644
--- a/app/assets/javascripts/ide/stores/getters.js
+++ b/app/assets/javascripts/ide/stores/getters.js
@@ -64,6 +64,7 @@ export const allBlobs = state =>
export const getChangedFile = state => path => state.changedFiles.find(f => f.path === path);
export const getStagedFile = state => path => state.stagedFiles.find(f => f.path === path);
+export const getOpenFile = state => path => state.openFiles.find(f => f.path === path);
export const lastOpenedFile = state =>
[...state.changedFiles, ...state.stagedFiles].sort((a, b) => b.lastOpenedAt - a.lastOpenedAt)[0];
diff --git a/app/assets/javascripts/ide/stores/mutations/file.js b/app/assets/javascripts/ide/stores/mutations/file.js
index 8caeb2d73b2..1b126352330 100644
--- a/app/assets/javascripts/ide/stores/mutations/file.js
+++ b/app/assets/javascripts/ide/stores/mutations/file.js
@@ -164,31 +164,32 @@ export default {
changedFiles: state.changedFiles.filter(f => f.path !== path),
});
},
- [types.STAGE_CHANGE](state, path) {
+ [types.STAGE_CHANGE](state, { path, diffInfo }) {
const stagedFile = state.stagedFiles.find(f => f.path === path);
Object.assign(state, {
changedFiles: state.changedFiles.filter(f => f.path !== path),
entries: Object.assign(state.entries, {
[path]: Object.assign(state.entries[path], {
- staged: true,
+ staged: diffInfo.exists,
+ changed: diffInfo.changed,
+ tempFile: diffInfo.tempFile,
+ deleted: diffInfo.deleted,
}),
}),
});
if (stagedFile) {
- Object.assign(stagedFile, {
- ...state.entries[path],
- });
+ Object.assign(stagedFile, { ...state.entries[path] });
} else {
- Object.assign(state, {
- stagedFiles: state.stagedFiles.concat({
- ...state.entries[path],
- }),
- });
+ state.stagedFiles = [...state.stagedFiles, { ...state.entries[path] }];
+ }
+
+ if (!diffInfo.exists) {
+ state.stagedFiles = state.stagedFiles.filter(f => f.path !== path);
}
},
- [types.UNSTAGE_CHANGE](state, path) {
+ [types.UNSTAGE_CHANGE](state, { path, diffInfo }) {
const changedFile = state.changedFiles.find(f => f.path === path);
const stagedFile = state.stagedFiles.find(f => f.path === path);
@@ -201,9 +202,11 @@ export default {
changed: true,
});
- Object.assign(state, {
- changedFiles: state.changedFiles.concat(state.entries[path]),
- });
+ state.changedFiles = state.changedFiles.concat(state.entries[path]);
+ }
+
+ if (!diffInfo.exists) {
+ state.changedFiles = state.changedFiles.filter(f => f.path !== path);
}
Object.assign(state, {
@@ -211,6 +214,9 @@ export default {
entries: Object.assign(state.entries, {
[path]: Object.assign(state.entries[path], {
staged: false,
+ changed: diffInfo.changed,
+ tempFile: diffInfo.tempFile,
+ deleted: diffInfo.deleted,
}),
}),
});
diff --git a/changelogs/unreleased/39498-part-3.yml b/changelogs/unreleased/39498-part-3.yml
new file mode 100644
index 00000000000..94475a2520c
--- /dev/null
+++ b/changelogs/unreleased/39498-part-3.yml
@@ -0,0 +1,5 @@
+---
+title: "!21542 Part 3: Handle edge cases in stage and unstage mutations"
+merge_request: 21676
+author:
+type: fixed
diff --git a/changelogs/unreleased/dast_mr_reports_feature_flag.yml b/changelogs/unreleased/dast_mr_reports_feature_flag.yml
new file mode 100644
index 00000000000..21ff19cc1bf
--- /dev/null
+++ b/changelogs/unreleased/dast_mr_reports_feature_flag.yml
@@ -0,0 +1,5 @@
+---
+title: Turns on backend MR reports for DAST by default
+merge_request: 22001
+author:
+type: changed
diff --git a/doc/api/issue_links.md b/doc/api/issue_links.md
index b7e21310a19..9351b3e4dd5 100644
--- a/doc/api/issue_links.md
+++ b/doc/api/issue_links.md
@@ -57,7 +57,7 @@ Parameters:
Creates a two-way relation between two issues. User must be allowed to update both issues in order to succeed.
```
-POST /projects/:id/issues/:issue_iid/links/:target_project_id/:target_issue_iid
+POST /projects/:id/issues/:issue_iid/links
```
| Attribute | Type | Required | Description |
@@ -67,6 +67,12 @@ POST /projects/:id/issues/:issue_iid/links/:target_project_id/:target_issue_iid
| `target_project_id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) of a target project |
| `target_issue_iid` | integer/string | yes | The internal ID of a target project's issue |
+```bash
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/4/issues/1/links?target_project_id=5&target_issue_iid=1"
+```
+
+Example response:
+
```json
{
"source_issue" : {
diff --git a/doc/user/packages/index.md b/doc/user/packages/index.md
index 613b4c975f4..dda43390cf1 100644
--- a/doc/user/packages/index.md
+++ b/doc/user/packages/index.md
@@ -22,3 +22,9 @@ guide you through the process. Or check out how other members of the commmunity
are adding support for [PHP](https://gitlab.com/gitlab-org/gitlab/merge_requests/17417) or [Terraform](https://gitlab.com/gitlab-org/gitlab/merge_requests/18834).
NOTE: **Note** We are especially interested in adding support for [PyPi](https://gitlab.com/gitlab-org/gitlab/issues/10483), [RubyGems](https://gitlab.com/gitlab-org/gitlab/issues/803), [Debian](https://gitlab.com/gitlab-org/gitlab/issues/5835), and [RPM](https://gitlab.com/gitlab-org/gitlab/issues/5932).
+
+## Package workflows
+
+Learning how to use the GitLab Package Registry will help you build your own custom package workflow.
+
+[Use a project as a package registry](./workflows/project_registry.md) to publish all of your packages to one project.
diff --git a/doc/user/packages/workflows/project_registry.md b/doc/user/packages/workflows/project_registry.md
new file mode 100644
index 00000000000..57befc4ecb8
--- /dev/null
+++ b/doc/user/packages/workflows/project_registry.md
@@ -0,0 +1,85 @@
+# Project as a package registry
+
+Using the features of the package registry, it is possible to use one project to store all of your packages.
+
+This guide mirrors the creation of [this package registry](https://gitlab.com/sabrams/my-package-registry).
+
+For the video version, see [Single Project Package Registry Demo](https://youtu.be/ui2nNBwN35c).
+
+## How does this work?
+
+You might be wondering "how is it possible to upload two packages from different codebases to the same project on GitLab?".
+
+It is easy to forget that a package on GitLab belongs to a project, but a project does not have to be a code repository.
+The code used to build your packages can be stored anywhere - maybe it is another project on GitLab, or maybe a completely
+different system altogether. All that matters is that when you configure your remote repositories for those packages, you
+point them at the same project on GitLab.
+
+## Why would I do this?
+
+There are a few reasons you might want to publish all your packages to one project on GitLab:
+
+1. You want to publish your packages on GitLab, but to a project that is different from where your code is stored.
+1. You would like to group packages together in ways that make sense for your usage (all NPM packages in one project,
+ all packages being used by a specific department in one project, all private packages in one project, etc.)
+1. You want to use one remote for all of your packages when installing them into other projects.
+1. You would like to migrate your packages to a single place on GitLab from a third-party package registry and do not
+ want to worry about setting up separate projects for each package.
+1. You want to have your CI pipelines build all of your packages to one project so the individual responsible for
+validating packages can manage them all in one place.
+
+## Example walkthrough
+
+There is no functionality specific to this feature. All we are doing is taking advantage of functionality available in each
+of the package management systems to publish packages of different types to the same place.
+
+Let's take a look at how you might create a public place to hold all of your public packages.
+
+### Create a project
+
+First, create a new project on GitLab. It does not have to have any code or content. Make note of the project ID
+displayed on the project overview page, as you will need this later.
+
+### Create an access token
+
+All of the package repositories available on the GitLab package registry are accessible using [GitLab personal access
+tokens](../../profile/personal_access_tokens.md).
+
+While using CI, you can alternatively use CI job tokens (`CI_JOB_TOKEN`) to authenticate.
+
+### Configure your local project for the GitLab registry and upload
+
+There are many ways to use this feature. You can upload all types of packages to the same project,
+split things up based on package type, or package visibility level.
+
+The purpose of this tutorial is to demonstrate the root idea that one project can hold many unrelated
+packages, and to allow you to discover the best way to use this functionality yourself.
+
+#### NPM
+
+If you are using NPM, this involves creating an `.npmrc` file and adding the appropriate URL for uploading packages
+to your project using your project ID, then adding a section to your `package.json` file with a similar URL.
+
+Follow
+the instructions in the [GitLab NPM Registry documentation](../npm_registry/index.md#authenticating-to-the-gitlab-npm-registry). Once
+you do this, you will be able to push your NPM package to your project using `npm publish`, as described in the
+[uploading packages](../npm_registry/index.md#uploading-packages) section of the docs.
+
+#### Maven
+
+If you are using Maven, this involves updating your `pom.xml` file with distribution sections, including the
+appropriate URL for your project, as described in the [GitLab Maven Repository documentation](../maven_repository/index.md#project-level-maven-endpoint).
+Then, you need to add a `settings.xml` file and [include your access token](../maven_repository/index.md#authenticating-with-a-personal-access-token).
+Now you can [deploy Maven packages](../maven_repository/index.md#uploading-packages) to your project.
+
+#### Conan
+
+For Conan, first you need to add GitLab as a Conan registry remote. Follow the instructions in the [GitLab Conan Repository docs](../conan_repository/index.md#setting-the-conan-remote-to-the-gitlab-package-registry)
+to do so. Then, create your package using the plus-separated (`+`) project path as your Conan user. For example,
+if your project is located at `https://gitlab.com/foo/bar/my-proj`, then you can [create your Conan package](../conan_repository/index.md)
+using `conan create . foo+bar+my-proj/channel`, where `channel` is your package channel (`stable`, `beta`, etc.). Once your package
+is created, you are ready to [upload your package](../conan_repository/index.md#uploading-a-package) depending on your final package recipe. For example:
+
+```sh
+CONAN_LOGIN_USERNAME=<gitlab-username> CONAN_PASSWORD=<personal_access_token> conan upload MyPackage/1.0.0@foo+bar+my-proj/channel --all --remote=gitlab
+```
diff --git a/spec/frontend/__mocks__/@gitlab/ui.js b/spec/frontend/__mocks__/@gitlab/ui.js
new file mode 100644
index 00000000000..ef97cb11424
--- /dev/null
+++ b/spec/frontend/__mocks__/@gitlab/ui.js
@@ -0,0 +1,19 @@
+export * from '@gitlab/ui';
+
+/**
+ * The @gitlab/ui tooltip directive requires awkward and distracting set up in tests
+ * for components that use it (e.g., `attachToDocument: true` and `sync: true` passed
+ * to the `mount` helper from `vue-test-utils`).
+ *
+ * This mock decouples those tests from the implementation, removing the need to set
+ * them up specially just for these tooltips.
+ */
+export const GlTooltipDirective = {
+ bind() {},
+};
+
+export const GlTooltip = {
+ render(h) {
+ return h('div', this.$attrs, this.$slots.default);
+ },
+};
diff --git a/spec/frontend/boards/issue_card_spec.js b/spec/frontend/boards/issue_card_spec.js
index c7ab477c0af..4a0a3497620 100644
--- a/spec/frontend/boards/issue_card_spec.js
+++ b/spec/frontend/boards/issue_card_spec.js
@@ -267,17 +267,13 @@ describe('Issue card component', () => {
});
it('renders label', () => {
- const nodes = wrapper
- .findAll('.badge')
- .wrappers.map(label => label.attributes('data-original-title'));
+ const nodes = wrapper.findAll('.badge').wrappers.map(label => label.attributes('title'));
expect(nodes.includes(label1.description)).toBe(true);
});
it('sets label description as title', () => {
- expect(wrapper.find('.badge').attributes('data-original-title')).toContain(
- label1.description,
- );
+ expect(wrapper.find('.badge').attributes('title')).toContain(label1.description);
});
it('sets background color of button', () => {
diff --git a/spec/frontend/diffs/components/compare_versions_spec.js b/spec/frontend/diffs/components/compare_versions_spec.js
index 9900fcdb6e1..dcce6f1fa7a 100644
--- a/spec/frontend/diffs/components/compare_versions_spec.js
+++ b/spec/frontend/diffs/components/compare_versions_spec.js
@@ -49,7 +49,7 @@ describe('CompareVersions', () => {
const treeListBtn = wrapper.find('.js-toggle-tree-list');
expect(treeListBtn.exists()).toBe(true);
- expect(treeListBtn.attributes('data-original-title')).toBe('Hide file browser');
+ expect(treeListBtn.attributes('title')).toBe('Hide file browser');
expect(treeListBtn.findAll(Icon).length).not.toBe(0);
expect(treeListBtn.find(Icon).props('name')).toBe('collapse-left');
});
diff --git a/spec/frontend/diffs/components/diff_file_header_spec.js b/spec/frontend/diffs/components/diff_file_header_spec.js
index 48fd6dd6f58..f2d07d3d4b2 100644
--- a/spec/frontend/diffs/components/diff_file_header_spec.js
+++ b/spec/frontend/diffs/components/diff_file_header_spec.js
@@ -329,7 +329,7 @@ describe('DiffFileHeader component', () => {
addMergeRequestButtons: true,
});
expect(findViewFileButton().attributes('href')).toBe(viewPath);
- expect(findViewFileButton().attributes('data-original-title')).toEqual(
+ expect(findViewFileButton().attributes('title')).toEqual(
`View file @ ${diffFile.content_sha.substr(0, 8)}`,
);
});
diff --git a/spec/frontend/environments/environment_monitoring_spec.js b/spec/frontend/environments/environment_monitoring_spec.js
index 8e67f799dc0..22241d5120b 100644
--- a/spec/frontend/environments/environment_monitoring_spec.js
+++ b/spec/frontend/environments/environment_monitoring_spec.js
@@ -33,7 +33,7 @@ describe('Monitoring Component', () => {
it('should render a link to environment monitoring page', () => {
expect(wrapper.attributes('href')).toEqual(monitoringUrl);
expect(findIconsByName('chart').length).toBe(1);
- expect(wrapper.attributes('data-original-title')).toBe('Monitoring');
+ expect(wrapper.attributes('title')).toBe('Monitoring');
expect(wrapper.attributes('aria-label')).toBe('Monitoring');
});
});
diff --git a/spec/frontend/environments/environment_stop_spec.js b/spec/frontend/environments/environment_stop_spec.js
index ab714728311..be029d48a56 100644
--- a/spec/frontend/environments/environment_stop_spec.js
+++ b/spec/frontend/environments/environment_stop_spec.js
@@ -29,7 +29,7 @@ describe('Stop Component', () => {
it('should render a button to stop the environment', () => {
expect(findButton().exists()).toBe(true);
- expect(wrapper.attributes('data-original-title')).toEqual('Stop environment');
+ expect(wrapper.attributes('title')).toEqual('Stop environment');
});
it('emits requestStopEnvironment in the event hub when button is clicked', () => {
diff --git a/spec/frontend/environments/environment_terminal_button_spec.js b/spec/frontend/environments/environment_terminal_button_spec.js
index 9aa2b82736c..058940c0e98 100644
--- a/spec/frontend/environments/environment_terminal_button_spec.js
+++ b/spec/frontend/environments/environment_terminal_button_spec.js
@@ -25,7 +25,7 @@ describe('Stop Component', () => {
it('should render a link to open a web terminal with the provided path', () => {
expect(wrapper.is('a')).toBe(true);
- expect(wrapper.attributes('data-original-title')).toBe('Terminal');
+ expect(wrapper.attributes('title')).toBe('Terminal');
expect(wrapper.attributes('aria-label')).toBe('Terminal');
expect(wrapper.attributes('href')).toBe(terminalPath);
});
diff --git a/spec/frontend/ide/stores/actions/file_spec.js b/spec/frontend/ide/stores/actions/file_spec.js
index 283ea266821..e9a657ffbfc 100644
--- a/spec/frontend/ide/stores/actions/file_spec.js
+++ b/spec/frontend/ide/stores/actions/file_spec.js
@@ -1,20 +1,20 @@
import Vue from 'vue';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
-import store from '~/ide/stores';
+import { createStore } from '~/ide/stores';
import * as actions from '~/ide/stores/actions/file';
import * as types from '~/ide/stores/mutation_types';
import service from '~/ide/services';
import router from '~/ide/ide_router';
import eventHub from '~/ide/eventhub';
-import { file, resetStore } from '../../helpers';
-import testAction from '../../../helpers/vuex_action_helper';
+import { file } from '../../helpers';
const RELATIVE_URL_ROOT = '/gitlab';
describe('IDE store file actions', () => {
let mock;
let originalGon;
+ let store;
beforeEach(() => {
mock = new MockAdapter(axios);
@@ -24,12 +24,15 @@ describe('IDE store file actions', () => {
relative_url_root: RELATIVE_URL_ROOT,
};
+ store = createStore();
+
+ jest.spyOn(store, 'commit');
+ jest.spyOn(store, 'dispatch');
jest.spyOn(router, 'push').mockImplementation(() => {});
});
afterEach(() => {
mock.restore();
- resetStore(store);
window.gon = originalGon;
});
@@ -663,30 +666,33 @@ describe('IDE store file actions', () => {
});
describe('stageChange', () => {
- it('calls STAGE_CHANGE with file path', done => {
- testAction(
- actions.stageChange,
- 'path',
- store.state,
- [
- { type: types.STAGE_CHANGE, payload: 'path' },
- { type: types.SET_LAST_COMMIT_MSG, payload: '' },
- ],
- [],
- done,
+ it('calls STAGE_CHANGE with file path', () => {
+ const f = { ...file('path'), content: 'old' };
+
+ store.state.entries[f.path] = f;
+
+ actions.stageChange(store, 'path');
+
+ expect(store.commit).toHaveBeenCalledWith(
+ types.STAGE_CHANGE,
+ expect.objectContaining({ path: 'path' }),
);
+ expect(store.commit).toHaveBeenCalledWith(types.SET_LAST_COMMIT_MSG, '');
});
});
describe('unstageChange', () => {
- it('calls UNSTAGE_CHANGE with file path', done => {
- testAction(
- actions.unstageChange,
- 'path',
- store.state,
- [{ type: types.UNSTAGE_CHANGE, payload: 'path' }],
- [],
- done,
+ it('calls UNSTAGE_CHANGE with file path', () => {
+ const f = { ...file('path'), content: 'old' };
+
+ store.state.entries[f.path] = f;
+ store.state.stagedFiles.push({ f, content: 'new' });
+
+ actions.unstageChange(store, 'path');
+
+ expect(store.commit).toHaveBeenCalledWith(
+ types.UNSTAGE_CHANGE,
+ expect.objectContaining({ path: 'path' }),
);
});
});
diff --git a/spec/frontend/ide/stores/mutations/file_spec.js b/spec/frontend/ide/stores/mutations/file_spec.js
index 91506c1b46c..8cb386d27e5 100644
--- a/spec/frontend/ide/stores/mutations/file_spec.js
+++ b/spec/frontend/ide/stores/mutations/file_spec.js
@@ -1,14 +1,16 @@
import mutations from '~/ide/stores/mutations/file';
-import state from '~/ide/stores/state';
+import { createStore } from '~/ide/stores';
import { FILE_VIEW_MODE_PREVIEW } from '~/ide/constants';
import { file } from '../../helpers';
describe('IDE store file mutations', () => {
let localState;
+ let localStore;
let localFile;
beforeEach(() => {
- localState = state();
+ localStore = createStore();
+ localState = localStore.state;
localFile = { ...file(), type: 'blob' };
localState.entries[localFile.path] = localFile;
@@ -333,44 +335,154 @@ describe('IDE store file mutations', () => {
});
});
- describe('STAGE_CHANGE', () => {
- beforeEach(() => {
- mutations.STAGE_CHANGE(localState, localFile.path);
- });
+ describe.each`
+ mutationName | mutation | addedTo | removedFrom | staged | changedFilesCount | stagedFilesCount
+ ${'STAGE_CHANGE'} | ${mutations.STAGE_CHANGE} | ${'stagedFiles'} | ${'changedFiles'} | ${true} | ${0} | ${1}
+ ${'UNSTAGE_CHANGE'} | ${mutations.UNSTAGE_CHANGE} | ${'changedFiles'} | ${'stagedFiles'} | ${false} | ${1} | ${0}
+ `(
+ '$mutationName',
+ ({ mutation, changedFilesCount, removedFrom, addedTo, staged, stagedFilesCount }) => {
+ let unstagedFile;
+ let stagedFile;
+
+ beforeEach(() => {
+ unstagedFile = {
+ ...file('file'),
+ type: 'blob',
+ raw: 'original content',
+ content: 'changed content',
+ };
+
+ stagedFile = {
+ ...unstagedFile,
+ content: 'staged content',
+ staged: true,
+ };
+
+ localState.changedFiles.push(unstagedFile);
+ localState.stagedFiles.push(stagedFile);
+ localState.entries[unstagedFile.path] = unstagedFile;
+ });
- it('adds file into stagedFiles array', () => {
- expect(localState.stagedFiles.length).toBe(1);
- expect(localState.stagedFiles[0]).toEqual(localFile);
- });
+ it('removes all changes of a file if staged and unstaged change contents are equal', () => {
+ unstagedFile.content = 'original content';
- it('updates stagedFile if it is already staged', () => {
- localFile.raw = 'testing 123';
+ mutation(localState, {
+ path: unstagedFile.path,
+ diffInfo: localStore.getters.getDiffInfo(unstagedFile.path),
+ });
- mutations.STAGE_CHANGE(localState, localFile.path);
+ expect(localState.entries.file).toEqual(
+ expect.objectContaining({
+ content: 'original content',
+ staged: false,
+ changed: false,
+ }),
+ );
- expect(localState.stagedFiles.length).toBe(1);
- expect(localState.stagedFiles[0].raw).toEqual('testing 123');
- });
- });
+ expect(localState.stagedFiles.length).toBe(0);
+ expect(localState.changedFiles.length).toBe(0);
+ });
- describe('UNSTAGE_CHANGE', () => {
- let f;
+ it('removes all changes of a file if a file is deleted and a new file with same content is added', () => {
+ stagedFile.deleted = true;
+ unstagedFile.tempFile = true;
+ unstagedFile.content = 'original content';
- beforeEach(() => {
- f = { ...file(), type: 'blob', staged: true };
+ mutation(localState, {
+ path: unstagedFile.path,
+ diffInfo: localStore.getters.getDiffInfo(unstagedFile.path),
+ });
- localState.stagedFiles.push(f);
- localState.changedFiles.push(f);
- localState.entries[f.path] = f;
- });
+ expect(localState.stagedFiles.length).toBe(0);
+ expect(localState.changedFiles.length).toBe(0);
- it('removes from stagedFiles array', () => {
- mutations.UNSTAGE_CHANGE(localState, f.path);
+ expect(localState.entries.file).toEqual(
+ expect.objectContaining({
+ content: 'original content',
+ deleted: false,
+ tempFile: false,
+ }),
+ );
+ });
- expect(localState.stagedFiles.length).toBe(0);
- expect(localState.changedFiles.length).toBe(1);
- });
- });
+ it('merges deleted and added file into a changed file if the contents differ', () => {
+ stagedFile.deleted = true;
+ unstagedFile.tempFile = true;
+ unstagedFile.content = 'hello';
+
+ mutation(localState, {
+ path: unstagedFile.path,
+ diffInfo: localStore.getters.getDiffInfo(unstagedFile.path),
+ });
+
+ expect(localState.stagedFiles.length).toBe(stagedFilesCount);
+ expect(localState.changedFiles.length).toBe(changedFilesCount);
+
+ expect(unstagedFile).toEqual(
+ expect.objectContaining({
+ content: 'hello',
+ staged,
+ deleted: false,
+ tempFile: false,
+ changed: true,
+ }),
+ );
+ });
+
+ it('does not remove file from stagedFiles and changedFiles if the file was renamed, even if the contents are equal', () => {
+ unstagedFile.content = 'original content';
+ unstagedFile.prevPath = 'old_file';
+
+ mutation(localState, {
+ path: unstagedFile.path,
+ diffInfo: localStore.getters.getDiffInfo(unstagedFile.path),
+ });
+
+ expect(localState.entries.file).toEqual(
+ expect.objectContaining({
+ content: 'original content',
+ staged,
+ changed: false,
+ prevPath: 'old_file',
+ }),
+ );
+
+ expect(localState.stagedFiles.length).toBe(stagedFilesCount);
+ expect(localState.changedFiles.length).toBe(changedFilesCount);
+ });
+
+ it(`removes file from ${removedFrom} array and adds it into ${addedTo} array`, () => {
+ localState.stagedFiles.length = 0;
+
+ mutation(localState, {
+ path: unstagedFile.path,
+ diffInfo: localStore.getters.getDiffInfo(unstagedFile.path),
+ });
+
+ expect(localState.stagedFiles.length).toBe(stagedFilesCount);
+ expect(localState.changedFiles.length).toBe(changedFilesCount);
+
+ const f = localState.stagedFiles[0] || localState.changedFiles[0];
+ expect(f).toEqual(unstagedFile);
+ });
+
+ it(`updates file in ${addedTo} array if it is was already present in it`, () => {
+ unstagedFile.raw = 'testing 123';
+
+ mutation(localState, {
+ path: unstagedFile.path,
+ diffInfo: localStore.getters.getDiffInfo(unstagedFile.path),
+ });
+
+ expect(localState.stagedFiles.length).toBe(stagedFilesCount);
+ expect(localState.changedFiles.length).toBe(changedFilesCount);
+
+ const f = localState.stagedFiles[0] || localState.changedFiles[0];
+ expect(f.raw).toEqual('testing 123');
+ });
+ },
+ );
describe('TOGGLE_FILE_CHANGED', () => {
it('updates file changed status', () => {
diff --git a/spec/frontend/issuable_suggestions/components/item_spec.js b/spec/frontend/issuable_suggestions/components/item_spec.js
index 10fba238506..eeea8960658 100644
--- a/spec/frontend/issuable_suggestions/components/item_spec.js
+++ b/spec/frontend/issuable_suggestions/components/item_spec.js
@@ -135,7 +135,7 @@ describe('Issuable suggestions suggestion component', () => {
const icon = vm.find(Icon);
expect(icon.props('name')).toBe('eye-slash');
- expect(icon.attributes('data-original-title')).toBe('Confidential');
+ expect(icon.attributes('title')).toBe('Confidential');
});
});
});
diff --git a/spec/frontend/issuables_list/components/issuable_spec.js b/spec/frontend/issuables_list/components/issuable_spec.js
index b6851a0e24c..b4d0bd47d65 100644
--- a/spec/frontend/issuables_list/components/issuable_spec.js
+++ b/spec/frontend/issuables_list/components/issuable_spec.js
@@ -70,7 +70,7 @@ describe('Issuable component', () => {
const findTaskStatus = () => wrapper.find('.task-status');
const findOpenedAgoContainer = () => wrapper.find({ ref: 'openedAgoByContainer' });
const findMilestone = () => wrapper.find('.js-milestone');
- const findMilestoneTooltip = () => findMilestone().attributes('data-original-title');
+ const findMilestoneTooltip = () => findMilestone().attributes('title');
const findDueDate = () => wrapper.find('.js-due-date');
const findLabelContainer = () => wrapper.find('.js-labels');
const findLabelLinks = () => findLabelContainer().findAll(GlLink);
@@ -240,7 +240,7 @@ describe('Issuable component', () => {
const labels = findLabelLinks().wrappers.map(label => ({
href: label.attributes('href'),
text: label.text(),
- tooltip: label.find('span').attributes('data-original-title'),
+ tooltip: label.find('span').attributes('title'),
}));
const expected = testLabels.map(label => ({
diff --git a/spec/frontend/notes/components/__snapshots__/discussion_jump_to_next_button_spec.js.snap b/spec/frontend/notes/components/__snapshots__/discussion_jump_to_next_button_spec.js.snap
index b29d093130a..1e466f266ed 100644
--- a/spec/frontend/notes/components/__snapshots__/discussion_jump_to_next_button_spec.js.snap
+++ b/spec/frontend/notes/components/__snapshots__/discussion_jump_to_next_button_spec.js.snap
@@ -7,8 +7,7 @@ exports[`JumpToNextDiscussionButton matches the snapshot 1`] = `
>
<button
class="btn btn-default discussion-next-btn"
- data-original-title="Jump to next unresolved discussion"
- title=""
+ title="Jump to next unresolved discussion"
>
<icon-stub
name="comment-next"
diff --git a/spec/frontend/pipelines/graph/action_component_spec.js b/spec/frontend/pipelines/graph/action_component_spec.js
index a8fddd5fff2..a7e504af231 100644
--- a/spec/frontend/pipelines/graph/action_component_spec.js
+++ b/spec/frontend/pipelines/graph/action_component_spec.js
@@ -30,7 +30,7 @@ describe('pipeline graph action component', () => {
});
it('should render the provided title as a bootstrap tooltip', () => {
- expect(wrapper.attributes('data-original-title')).toBe('bar');
+ expect(wrapper.attributes('title')).toBe('bar');
});
it('should update bootstrap tooltip when title changes', done => {
@@ -39,7 +39,7 @@ describe('pipeline graph action component', () => {
wrapper.vm
.$nextTick()
.then(() => {
- expect(wrapper.attributes('data-original-title')).toBe('changed');
+ expect(wrapper.attributes('title')).toBe('changed');
})
.then(done)
.catch(done.fail);
diff --git a/spec/frontend/pipelines/graph/job_item_spec.js b/spec/frontend/pipelines/graph/job_item_spec.js
index c79af95b3f3..22e1881ead4 100644
--- a/spec/frontend/pipelines/graph/job_item_spec.js
+++ b/spec/frontend/pipelines/graph/job_item_spec.js
@@ -43,9 +43,7 @@ describe('pipeline graph job item', () => {
expect(link.attributes('href')).toBe(mockJob.status.details_path);
- expect(link.attributes('data-original-title')).toEqual(
- `${mockJob.name} - ${mockJob.status.label}`,
- );
+ expect(link.attributes('title')).toEqual(`${mockJob.name} - ${mockJob.status.label}`);
expect(wrapper.find('.js-status-icon-success')).toBeDefined();
@@ -110,9 +108,7 @@ describe('pipeline graph job item', () => {
},
});
- expect(wrapper.find('.js-job-component-tooltip').attributes('data-original-title')).toBe(
- 'test',
- );
+ expect(wrapper.find('.js-job-component-tooltip').attributes('title')).toBe('test');
});
it('should not render status label when it is provided', () => {
@@ -128,7 +124,7 @@ describe('pipeline graph job item', () => {
},
});
- expect(wrapper.find('.js-job-component-tooltip').attributes('data-original-title')).toEqual(
+ expect(wrapper.find('.js-job-component-tooltip').attributes('title')).toEqual(
'test - success',
);
});
@@ -140,7 +136,7 @@ describe('pipeline graph job item', () => {
job: delayedJobFixture,
});
- expect(wrapper.find('.js-pipeline-graph-job-link').attributes('data-original-title')).toEqual(
+ expect(wrapper.find('.js-pipeline-graph-job-link').attributes('title')).toEqual(
`delayed job - delayed manual action (${wrapper.vm.remainingTime})`,
);
});
diff --git a/spec/frontend/pipelines/graph/linked_pipeline_spec.js b/spec/frontend/pipelines/graph/linked_pipeline_spec.js
index c355d653203..b5fb1a94ebd 100644
--- a/spec/frontend/pipelines/graph/linked_pipeline_spec.js
+++ b/spec/frontend/pipelines/graph/linked_pipeline_spec.js
@@ -65,7 +65,7 @@ describe('Linked pipeline', () => {
it('should render the tooltip text as the title attribute', () => {
const tooltipRef = wrapper.find('.js-linked-pipeline-content');
- const titleAttr = tooltipRef.attributes('data-original-title');
+ const titleAttr = tooltipRef.attributes('title');
expect(titleAttr).toContain(mockPipeline.project.name);
expect(titleAttr).toContain(mockPipeline.details.status.label);
diff --git a/spec/frontend/pipelines/pipeline_url_spec.js b/spec/frontend/pipelines/pipeline_url_spec.js
index 3c0c35e1f0f..0bb5ff159c5 100644
--- a/spec/frontend/pipelines/pipeline_url_spec.js
+++ b/spec/frontend/pipelines/pipeline_url_spec.js
@@ -105,8 +105,6 @@ describe('Pipeline Url Component', () => {
});
expect(wrapper.find('.js-pipeline-url-failure').text()).toContain('error');
- expect(wrapper.find('.js-pipeline-url-failure').attributes('data-original-title')).toContain(
- 'some reason',
- );
+ expect(wrapper.find('.js-pipeline-url-failure').attributes('title')).toContain('some reason');
});
});
diff --git a/spec/frontend/registry/list/components/__snapshots__/project_empty_state_spec.js.snap b/spec/frontend/registry/list/components/__snapshots__/project_empty_state_spec.js.snap
index 3084462f5ae..d11a9bdeb51 100644
--- a/spec/frontend/registry/list/components/__snapshots__/project_empty_state_spec.js.snap
+++ b/spec/frontend/registry/list/components/__snapshots__/project_empty_state_spec.js.snap
@@ -86,8 +86,7 @@ exports[`Registry Project Empty state to match the default snapshot 1`] = `
<button
class="btn input-group-text btn-secondary btn-default"
data-clipboard-text="docker login host"
- data-original-title="Copy login command"
- title=""
+ title="Copy login command"
type="button"
>
<svg
@@ -125,8 +124,7 @@ exports[`Registry Project Empty state to match the default snapshot 1`] = `
<button
class="btn input-group-text btn-secondary btn-default"
data-clipboard-text="docker build -t url ."
- data-original-title="Copy build command"
- title=""
+ title="Copy build command"
type="button"
>
<svg
@@ -156,8 +154,7 @@ exports[`Registry Project Empty state to match the default snapshot 1`] = `
<button
class="btn input-group-text btn-secondary btn-default"
data-clipboard-text="docker push url"
- data-original-title="Copy push command"
- title=""
+ title="Copy push command"
type="button"
>
<svg
diff --git a/spec/frontend/releases/list/components/evidence_block_spec.js b/spec/frontend/releases/list/components/evidence_block_spec.js
index e8a3eace216..959711983b8 100644
--- a/spec/frontend/releases/list/components/evidence_block_spec.js
+++ b/spec/frontend/releases/list/components/evidence_block_spec.js
@@ -39,7 +39,7 @@ describe('Evidence Block', () => {
});
it('renders the correct hover text for the download', () => {
- expect(wrapper.find(GlLink).attributes('data-original-title')).toBe('Download evidence JSON');
+ expect(wrapper.find(GlLink).attributes('title')).toBe('Download evidence JSON');
});
it('renders the correct file link for download', () => {
@@ -63,9 +63,7 @@ describe('Evidence Block', () => {
});
it('renders the correct hover text', () => {
- expect(wrapper.find(ClipboardButton).attributes('data-original-title')).toBe(
- 'Copy commit SHA',
- );
+ expect(wrapper.find(ClipboardButton).attributes('title')).toBe('Copy commit SHA');
});
it('copies the sha', () => {
diff --git a/spec/frontend/releases/list/components/release_block_milestone_info_spec.js b/spec/frontend/releases/list/components/release_block_milestone_info_spec.js
index 7179ab3d3cc..a52bd8a34b2 100644
--- a/spec/frontend/releases/list/components/release_block_milestone_info_spec.js
+++ b/spec/frontend/releases/list/components/release_block_milestone_info_spec.js
@@ -61,7 +61,7 @@ describe('Release block milestone info', () => {
expect(milestoneLink.text()).toBe(m.title);
expect(milestoneLink.attributes('href')).toBe(m.web_url);
- expect(milestoneLink.attributes('data-original-title')).toBe(m.description);
+ expect(milestoneLink.attributes('title')).toBe(m.description);
});
});
diff --git a/spec/frontend/releases/list/components/release_block_spec.js b/spec/frontend/releases/list/components/release_block_spec.js
index 38c5e4fc0a2..89691a83414 100644
--- a/spec/frontend/releases/list/components/release_block_spec.js
+++ b/spec/frontend/releases/list/components/release_block_spec.js
@@ -271,7 +271,7 @@ describe('Release block', () => {
expect(milestoneLink.attributes('href')).toBe(milestone.web_url);
- expect(milestoneLink.attributes('data-original-title')).toBe(milestone.description);
+ expect(milestoneLink.attributes('title')).toBe(milestone.description);
});
});
diff --git a/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap b/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
index 706c26403c0..60215b70d36 100644
--- a/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
+++ b/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
@@ -67,9 +67,8 @@ exports[`Repository last commit component renders commit widget 1`] = `
>
<gllink-stub
class="js-commit-pipeline"
- data-original-title="Commit: failed"
href="https://test.com/pipeline"
- title=""
+ title="Commit: failed"
>
<ciicon-stub
aria-label="Commit: failed"
@@ -174,9 +173,8 @@ exports[`Repository last commit component renders the signature HTML as returned
>
<gllink-stub
class="js-commit-pipeline"
- data-original-title="Commit: failed"
href="https://test.com/pipeline"
- title=""
+ title="Commit: failed"
>
<ciicon-stub
aria-label="Commit: failed"
diff --git a/spec/frontend/sidebar/assignees_spec.js b/spec/frontend/sidebar/assignees_spec.js
index 14b6da10991..4cc91c7ca6e 100644
--- a/spec/frontend/sidebar/assignees_spec.js
+++ b/spec/frontend/sidebar/assignees_spec.js
@@ -178,7 +178,7 @@ describe('Assignee component', () => {
const userItems = wrapper.findAll('.user-list .user-item a');
expect(userItems.length).toBe(3);
- expect(userItems.at(0).attributes('data-original-title')).toBe(users[2].name);
+ expect(userItems.at(0).attributes('title')).toBe(users[2].name);
});
it('passes the sorted assignees to the collapsed-assignee-list', () => {
diff --git a/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js b/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js
index 9b2e2e38366..5f2b00eaa23 100644
--- a/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js
+++ b/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js
@@ -33,7 +33,7 @@ describe('AssigneeAvatarLink component', () => {
wrapper.destroy();
});
- const findTooltipText = () => wrapper.attributes('data-original-title');
+ const findTooltipText = () => wrapper.attributes('title');
it('has the root url present in the assigneeUrl method', () => {
createComponent();
diff --git a/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js b/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js
index 6aa7b166804..4479b180b65 100644
--- a/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js
+++ b/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js
@@ -25,7 +25,7 @@ describe('CollapsedAssigneeList component', () => {
const findNoUsersIcon = () => wrapper.find('i[aria-label=None]');
const findAvatarCounter = () => wrapper.find('.avatar-counter');
const findAssignees = () => wrapper.findAll(CollapsedAssignee);
- const getTooltipTitle = () => wrapper.attributes('data-original-title');
+ const getTooltipTitle = () => wrapper.attributes('title');
afterEach(() => {
wrapper.destroy();
diff --git a/spec/frontend/vue_shared/components/changed_file_icon_spec.js b/spec/frontend/vue_shared/components/changed_file_icon_spec.js
index 2fabbe3d0f6..381d5dd289f 100644
--- a/spec/frontend/vue_shared/components/changed_file_icon_spec.js
+++ b/spec/frontend/vue_shared/components/changed_file_icon_spec.js
@@ -30,7 +30,7 @@ describe('Changed file icon', () => {
const findIcon = () => wrapper.find(Icon);
const findIconName = () => findIcon().props('name');
const findIconClasses = () => findIcon().classes();
- const findTooltipText = () => wrapper.attributes('data-original-title');
+ const findTooltipText = () => wrapper.attributes('title');
it('with isCentered true, adds center class', () => {
factory({
@@ -89,7 +89,7 @@ describe('Changed file icon', () => {
});
it('does not have tooltip text', () => {
- expect(findTooltipText()).toBe('');
+ expect(findTooltipText()).toBeFalsy();
});
});
diff --git a/spec/frontend/vue_shared/components/clipboard_button_spec.js b/spec/frontend/vue_shared/components/clipboard_button_spec.js
index 4fb6924daba..df66b90c26e 100644
--- a/spec/frontend/vue_shared/components/clipboard_button_spec.js
+++ b/spec/frontend/vue_shared/components/clipboard_button_spec.js
@@ -35,7 +35,7 @@ describe('clipboard button', () => {
});
it('should have a tooltip with default values', () => {
- expect(wrapper.attributes('data-original-title')).toBe('Copy this value');
+ expect(wrapper.attributes('title')).toBe('Copy this value');
});
it('should render provided classname', () => {
diff --git a/spec/frontend/vue_shared/components/commit_spec.js b/spec/frontend/vue_shared/components/commit_spec.js
index 67262eec0a5..34f3a54fce2 100644
--- a/spec/frontend/vue_shared/components/commit_spec.js
+++ b/spec/frontend/vue_shared/components/commit_spec.js
@@ -160,7 +160,7 @@ describe('Commit component', () => {
expect(refEl.attributes('href')).toBe(props.commitRef.ref_url);
- expect(refEl.attributes('data-original-title')).toBe(props.commitRef.name);
+ expect(refEl.attributes('title')).toBe(props.commitRef.name);
expect(wrapper.find('icon-stub[name="branch"]').exists()).toBe(true);
});
@@ -193,7 +193,7 @@ describe('Commit component', () => {
expect(refEl.attributes('href')).toBe(props.mergeRequestRef.path);
- expect(refEl.attributes('data-original-title')).toBe(props.mergeRequestRef.title);
+ expect(refEl.attributes('title')).toBe(props.mergeRequestRef.title);
expect(wrapper.find('icon-stub[name="git-merge"]').exists()).toBe(true);
});
diff --git a/spec/frontend/vue_shared/components/issue/issue_assignees_spec.js b/spec/frontend/vue_shared/components/issue/issue_assignees_spec.js
index dcae2f12833..5271227d3cd 100644
--- a/spec/frontend/vue_shared/components/issue/issue_assignees_spec.js
+++ b/spec/frontend/vue_shared/components/issue/issue_assignees_spec.js
@@ -66,7 +66,7 @@ describe('IssueAssigneesComponent', () => {
expect(findOverflowCounter().exists()).toBe(true);
expect(findOverflowCounter().text()).toEqual(expectedHidden.toString());
- expect(findOverflowCounter().attributes('data-original-title')).toEqual(
+ expect(findOverflowCounter().attributes('title')).toEqual(
`${hiddenCount} more assignees`,
);
});
diff --git a/spec/frontend/vue_shared/components/time_ago_tooltip_spec.js b/spec/frontend/vue_shared/components/time_ago_tooltip_spec.js
index f1f231c1a29..ebba0cc4ad4 100644
--- a/spec/frontend/vue_shared/components/time_ago_tooltip_spec.js
+++ b/spec/frontend/vue_shared/components/time_ago_tooltip_spec.js
@@ -25,7 +25,7 @@ describe('Time ago with tooltip component', () => {
});
const timeago = getTimeago();
- expect(vm.attributes('data-original-title')).toEqual(formatDate(timestamp));
+ expect(vm.attributes('title')).toEqual(formatDate(timestamp));
expect(vm.text()).toEqual(timeago.format(timestamp));
});
diff --git a/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js b/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js
index e76b2ca2d65..03bb88d1486 100644
--- a/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js
+++ b/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js
@@ -100,7 +100,7 @@ describe('User Avatar Image Component', () => {
it('does not render tooltip data attributes for on avatar image', () => {
const avatarImg = wrapper.find('img');
- expect(avatarImg.attributes('data-original-title')).toBeFalsy();
+ expect(avatarImg.attributes('title')).toBeFalsy();
expect(avatarImg.attributes('data-placement')).not.toBeDefined();
expect(avatarImg.attributes('data-container')).not.toBeDefined();
});
diff --git a/spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js b/spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js
index 7f5df02d51d..16993cc21c9 100644
--- a/spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js
+++ b/spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js
@@ -99,9 +99,9 @@ describe('User Avatar Link Component', () => {
});
it('should render text tooltip for <span>', () => {
- expect(
- wrapper.find('.js-user-avatar-link-username').attributes('data-original-title'),
- ).toEqual(defaultProps.tooltipText);
+ expect(wrapper.find('.js-user-avatar-link-username').attributes('title')).toEqual(
+ defaultProps.tooltipText,
+ );
});
it('should render text tooltip placement for <span>', () => {
diff --git a/spec/javascripts/ide/stores/actions_spec.js b/spec/javascripts/ide/stores/actions_spec.js
index cb03204d337..a9fc3bf65a6 100644
--- a/spec/javascripts/ide/stores/actions_spec.js
+++ b/spec/javascripts/ide/stores/actions_spec.js
@@ -18,19 +18,19 @@ import axios from '~/lib/utils/axios_utils';
import { createStore } from '~/ide/stores';
import * as types from '~/ide/stores/mutation_types';
import router from '~/ide/ide_router';
-import { resetStore, file } from '../helpers';
+import { file } from '../helpers';
import testAction from '../../helpers/vuex_action_helper';
import eventHub from '~/ide/eventhub';
-const store = createStore();
-
describe('Multi-file store actions', () => {
+ let store;
+
beforeEach(() => {
- spyOn(router, 'push');
- });
+ store = createStore();
- afterEach(() => {
- resetStore(store);
+ spyOn(store, 'commit').and.callThrough();
+ spyOn(store, 'dispatch').and.callThrough();
+ spyOn(router, 'push');
});
describe('redirectToUrl', () => {
@@ -390,58 +390,82 @@ describe('Multi-file store actions', () => {
});
});
- describe('stageAllChanges', () => {
- it('adds all files from changedFiles to stagedFiles', done => {
- const openFile = { ...file(), path: 'test' };
+ describe('stage/unstageAllChanges', () => {
+ let file1;
+ let file2;
- store.state.openFiles.push(openFile);
- store.state.stagedFiles.push(openFile);
- store.state.changedFiles.push(openFile, file('new'));
+ beforeEach(() => {
+ file1 = { ...file('test'), content: 'changed test', raw: 'test' };
+ file2 = { ...file('test2'), content: 'changed test2', raw: 'test2' };
- testAction(
- stageAllChanges,
- null,
- store.state,
- [
- { type: types.SET_LAST_COMMIT_MSG, payload: '' },
- { type: types.STAGE_CHANGE, payload: store.state.changedFiles[0].path },
- { type: types.STAGE_CHANGE, payload: store.state.changedFiles[1].path },
- ],
- [
- {
- type: 'openPendingTab',
- payload: { file: openFile, keyPrefix: 'staged' },
- },
- ],
- done,
- );
+ store.state.openFiles = [file1];
+ store.state.changedFiles = [file1];
+ store.state.stagedFiles = [{ ...file2, content: 'staged test' }];
+
+ store.state.entries = {
+ [file1.path]: { ...file1 },
+ [file2.path]: { ...file2 },
+ };
});
- });
- describe('unstageAllChanges', () => {
- it('removes all files from stagedFiles after unstaging', done => {
- const openFile = { ...file(), path: 'test' };
+ describe('stageAllChanges', () => {
+ it('adds all files from changedFiles to stagedFiles', () => {
+ stageAllChanges(store);
- store.state.openFiles.push(openFile);
- store.state.changedFiles.push(openFile);
- store.state.stagedFiles.push(openFile, file('new'));
+ expect(store.commit.calls.allArgs()).toEqual([
+ [types.SET_LAST_COMMIT_MSG, ''],
+ [types.STAGE_CHANGE, jasmine.objectContaining({ path: file1.path })],
+ ]);
+ });
- testAction(
- unstageAllChanges,
- null,
- store.state,
- [
- { type: types.UNSTAGE_CHANGE, payload: store.state.stagedFiles[0].path },
- { type: types.UNSTAGE_CHANGE, payload: store.state.stagedFiles[1].path },
- ],
- [
- {
- type: 'openPendingTab',
- payload: { file: openFile, keyPrefix: 'unstaged' },
- },
- ],
- done,
- );
+ it('opens pending tab if a change exists in that file', () => {
+ stageAllChanges(store);
+
+ expect(store.dispatch.calls.allArgs()).toEqual([
+ [
+ 'openPendingTab',
+ { file: { ...file1, staged: true, changed: true }, keyPrefix: 'staged' },
+ ],
+ ]);
+ });
+
+ it('does not open pending tab if no change exists in that file', () => {
+ store.state.entries[file1.path].content = 'test';
+ store.state.stagedFiles = [file1];
+ store.state.changedFiles = [store.state.entries[file1.path]];
+
+ stageAllChanges(store);
+
+ expect(store.dispatch).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('unstageAllChanges', () => {
+ it('removes all files from stagedFiles after unstaging', () => {
+ unstageAllChanges(store);
+
+ expect(store.commit.calls.allArgs()).toEqual([
+ [types.UNSTAGE_CHANGE, jasmine.objectContaining({ path: file2.path })],
+ ]);
+ });
+
+ it('opens pending tab if a change exists in that file', () => {
+ unstageAllChanges(store);
+
+ expect(store.dispatch.calls.allArgs()).toEqual([
+ ['openPendingTab', { file: file1, keyPrefix: 'unstaged' }],
+ ]);
+ });
+
+ it('does not open pending tab if no change exists in that file', () => {
+ store.state.entries[file1.path].content = 'test';
+ store.state.stagedFiles = [file1];
+ store.state.changedFiles = [store.state.entries[file1.path]];
+
+ unstageAllChanges(store);
+
+ expect(store.dispatch).not.toHaveBeenCalled();
+ });
});
});
@@ -752,10 +776,6 @@ describe('Multi-file store actions', () => {
});
});
- afterEach(() => {
- resetStore(store);
- });
-
it('by default renames an entry and adds to changed', done => {
testAction(
renameEntry,
@@ -966,18 +986,19 @@ describe('Multi-file store actions', () => {
describe('error', () => {
let dispatch;
- const callParams = [
- {
- commit() {},
- state: store.state,
- },
- {
- projectId: 'abc/def',
- branchId: 'master-testing',
- },
- ];
+ let callParams;
beforeEach(() => {
+ callParams = [
+ {
+ commit() {},
+ state: store.state,
+ },
+ {
+ projectId: 'abc/def',
+ branchId: 'master-testing',
+ },
+ ];
dispatch = jasmine.createSpy('dispatchSpy');
document.body.innerHTML += '<div class="flash-container"></div>';
});