summaryrefslogtreecommitdiff
path: root/doc/development/fe_guide
diff options
context:
space:
mode:
Diffstat (limited to 'doc/development/fe_guide')
-rw-r--r--doc/development/fe_guide/accessibility.md50
-rw-r--r--doc/development/fe_guide/content_editor.md116
-rw-r--r--doc/development/fe_guide/design_anti_patterns.md4
-rw-r--r--doc/development/fe_guide/editor_lite.md1
-rw-r--r--doc/development/fe_guide/event_tracking.md3
-rw-r--r--doc/development/fe_guide/frontend_faq.md10
-rw-r--r--doc/development/fe_guide/graphql.md11
-rw-r--r--doc/development/fe_guide/img/content_editor_highlevel_diagram.pngbin0 -> 47794 bytes
-rw-r--r--doc/development/fe_guide/index.md5
-rw-r--r--doc/development/fe_guide/style/vue.md9
-rw-r--r--doc/development/fe_guide/troubleshooting.md8
-rw-r--r--doc/development/fe_guide/vue.md44
-rw-r--r--doc/development/fe_guide/vuex.md3
13 files changed, 214 insertions, 50 deletions
diff --git a/doc/development/fe_guide/accessibility.md b/doc/development/fe_guide/accessibility.md
index ab1325c67a9..15818941b24 100644
--- a/doc/development/fe_guide/accessibility.md
+++ b/doc/development/fe_guide/accessibility.md
@@ -39,9 +39,20 @@ so when in doubt don't use `aria-*`, `role`, and `tabindex` and stick with seman
- [Clickable icons](#icons-that-are-clickable) are buttons, that is, `<gl-button icon="close" />` is used and not `<gl-icon />`.
- Icon-only buttons have an `aria-label`.
- Interactive elements can be [accessed with the Tab key](#support-keyboard-only-use) and have a visible focus state.
+- Elements with [tooltips](#tooltips) are focusable using the Tab key.
- Are any `role`, `tabindex` or `aria-*` attributes unnecessary?
- Can any `div` or `span` elements be replaced with a more semantic [HTML element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element) like `p`, `button`, or `time`?
+## Provide a good document outline
+
+[Headings are the primary mechanism used by screen reader users to navigate content](https://webaim.org/projects/screenreadersurvey8/#finding).
+Therefore, the structure of headings on a page should make sense, like a good table of contents.
+We should ensure that:
+
+- There is only one `h1` element on the page.
+- Heading levels are not skipped.
+- Heading levels are nested correctly.
+
## Provide accessible names for screen readers
To provide markup with accessible names, ensure every:
@@ -257,6 +268,9 @@ Image examples:
<!-- SVGs implicitly have a graphics role so if it is semantically an image we should apply `role="img"` -->
<svg role="img" :alt="__('A description of the image')" />
+
+<!-- A decorative image, hidden from screen readers -->
+<img :src="imagePath" :alt="" />
```
#### Buttons and links with descriptive accessible names
@@ -275,6 +289,14 @@ Buttons and links should have accessible names that are descriptive enough to be
<gl-link :href="url">{{ __("GitLab's accessibility page") }}</gl-link>
```
+#### Links styled like buttons
+
+Links can be styled like buttons using `GlButton`.
+
+```html
+ <gl-button :href="url">{{ __('Link styled as a button') }}</gl-button>
+```
+
## Role
In general, avoid using `role`.
@@ -336,7 +358,7 @@ Once the markup is semantically complete, use CSS to update it to its desired vi
<div role="button" tabindex="0" @click="expand">Expand</div>
<!-- good -->
-<gl-button @click="expand">Expand</gl-button>
+<gl-button class="gl-p-0!" category="tertiary" @click="expand">Expand</gl-button>
```
### Do not use `tabindex="0"` on interactive elements
@@ -423,6 +445,30 @@ Icons that are clickable are semantically buttons, so they should be rendered as
<gl-button icon="close" category="tertiary" :aria-label="__('Close')" @click="handleClick" />
```
+## Tooltips
+
+When adding tooltips, we must ensure that the element with the tooltip can receive focus so keyboard users can see the tooltip.
+If the element is a static one, such as an icon, we can enclose it in a button, which already is
+focusable, so we don't have to add `tabindex=0` to the icon.
+
+The following code snippet is a good example of an icon with a tooltip.
+
+- It is automatically focusable, as it is a button.
+- It is given an accessible name with `aria-label`, as it is a button with no text.
+- We can use the `gl-hover-bg-transparent!` class if we don't want the button's background to become gray on hover.
+- We can use the `gl-p-0!` class to remove the button padding, if needed.
+
+```html
+<gl-button
+ v-gl-tooltip
+ class="gl-hover-bg-transparent! gl-p-0!"
+ icon="warning"
+ category="tertiary"
+ :title="tooltipText"
+ :aria-label="__('Warning')"
+/>
+```
+
## Hiding elements
Use the following table to hide elements from users, when appropriate.
@@ -478,5 +524,3 @@ We have two options for Web accessibility testing:
- [The A11Y Project](https://www.a11yproject.com/) is a good resource for accessibility
- [Awesome Accessibility](https://github.com/brunopulis/awesome-a11y)
is a compilation of accessibility-related material
-- You can read [Chrome Accessibility Developer Tools'](https://github.com/GoogleChrome/accessibility-developer-tools)
- rules on its [Audit Rules page](https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules)
diff --git a/doc/development/fe_guide/content_editor.md b/doc/development/fe_guide/content_editor.md
new file mode 100644
index 00000000000..f6329f39636
--- /dev/null
+++ b/doc/development/fe_guide/content_editor.md
@@ -0,0 +1,116 @@
+---
+stage: Create
+group: Editor
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
+---
+
+# Content Editor **(FREE)**
+
+The Content Editor is a UI component that provides a WYSIWYG editing
+experience for [GitLab Flavored Markdown](../../user/markdown.md) (GFM) in the GitLab application.
+It also serves as the foundation for implementing Markdown-focused editors
+that target other engines, like static site generators.
+
+We use [tiptap 2.0](https://www.tiptap.dev/) and [ProseMirror](https://prosemirror.net/)
+to build the Content Editor. These frameworks provide a level of abstraction on top of
+the native
+[`contenteditable`](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Editable_content) web technology.
+
+## Architecture remarks
+
+At a high level, the Content Editor:
+
+- Imports arbitrary Markdown.
+- Renders it in a HTML editing area.
+- Exports it back to Markdown with changes introduced by the user.
+
+The Content Editor relies on the
+[Markdown API endpoint](../../api/markdown.md) to transform Markdown
+into HTML. It sends the Markdown input to the REST API and displays the API's
+HTML output in the editing area. The editor exports the content back to Markdown
+using a client-side library that serializes editable documents into Markdown.
+
+![Content Editor high level diagram](img/content_editor_highlevel_diagram.png)
+
+Check the [Content Editor technical design document](https://docs.google.com/document/d/1fKOiWpdHned4KOLVOOFYVvX1euEjMP5rTntUhpapdBg)
+for more information about the design decisions that drive the development of the editor.
+
+**NOTE**: We also designed the Content Editor to be extensible. We intend to provide
+more information about extension development for supporting new types of content in upcoming
+milestones.
+
+## GitLab Flavored Markdown support
+
+The [GitLab Flavored Markdown](../../user/markdown.md) extends
+the [CommonMark specification](https://spec.commonmark.org/0.29/) with support for a
+variety of content types like diagrams, math expressions, and tables. Supporting
+all GitLab Flavored Markdown content types in the Content Editor is a work in progress. For
+the status of the ongoing development for CommonMark and GitLab Flavored Markdown support, read:
+
+- [Basic Markdown formatting extensions](https://gitlab.com/groups/gitlab-org/-/epics/5404) epic.
+- [GitLab Flavored Markdown extensions](https://gitlab.com/groups/gitlab-org/-/epics/5438) epic.
+
+## Usage
+
+To include the Content Editor in your feature, import the `createContentEditor` factory
+function and the `ContentEditor` Vue component. `createContentEditor` sets up an instance
+of [tiptap's Editor class](https://www.tiptap.dev/api/editor) with all the necessary
+extensions to support editing GitLab Flavored Markdown content. It also creates
+a Markdown serializer that allows exporting tiptap's document format to Markdown.
+
+`createContentEditor` requires a `renderMarkdown` parameter invoked
+by the editor every time it needs to convert Markdown to HTML. The Content Editor
+does not provide a default value for this function yet.
+
+**NOTE**: The Content Editor is in an early development stage. Usage and development
+guidelines are subject to breaking changes in the upcoming months.
+
+```html
+<script>
+import { GlButton } from '@gitlab/ui';
+import { createContentEditor, ContentEditor } from '~/content_editor';
+import { __ } from '~/locale';
+import createFlash from '~/flash';
+
+export default {
+ components: {
+ ContentEditor,
+ GlButton,
+ },
+ data() {
+ return {
+ contentEditor: null,
+ }
+ },
+ created() {
+ this.contentEditor = createContentEditor({
+ renderMarkdown: (markdown) => Api.markdown({ text: markdown }),
+ });
+
+ try {
+ await this.contentEditor.setSerializedContent(this.content);
+ } catch (e) {
+ createFlash(__('There was an error loading content in the editor'), e);
+ }
+ },
+ methods: {
+ async save() {
+ await Api.updateContent({
+ content: this.contentEditor.getSerializedContent(),
+ });
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <content-editor :content-editor="contentEditor" />
+ <gl-button @click="save()">Save</gl-button>
+ </div>
+</template>
+```
+
+Call `setSerializedContent` to set initial Markdown in the Editor. This method is
+asynchronous because it makes an API request to render the Markdown input.
+`getSerializedContent` returns a Markdown string that represents the serialized
+version of the editable document.
diff --git a/doc/development/fe_guide/design_anti_patterns.md b/doc/development/fe_guide/design_anti_patterns.md
index ee4fceff927..0788921fce4 100644
--- a/doc/development/fe_guide/design_anti_patterns.md
+++ b/doc/development/fe_guide/design_anti_patterns.md
@@ -119,8 +119,8 @@ Here are some ills that Singletons often produce:
such as no clear ownership and no access control. These leads to high coupling situations that can
be buggy and difficult to untangle.
1. **Infectious.** Singletons are infectious, especially when they manage state. Consider the component
- [RepoEditor](https://gitlab.com/gitlab-org/gitlab/blob/27ad6cb7b76430fbcbaf850df68c338d6719ed2b/app%2Fassets%2Fjavascripts%2Fide%2Fcomponents%2Frepo_editor.vue#L0-1)
- used in the Web IDE. This component interfaces with a Singleton [Editor](https://gitlab.com/gitlab-org/gitlab/blob/862ad57c44ec758ef3942ac2e7a2bd40a37a9c59/app%2Fassets%2Fjavascripts%2Fide%2Flib%2Feditor.js#L21)
+ [RepoEditor](https://gitlab.com/gitlab-org/gitlab/-/blob/27ad6cb7b76430fbcbaf850df68c338d6719ed2b/app%2Fassets%2Fjavascripts%2Fide%2Fcomponents%2Frepo_editor.vue#L0-1)
+ used in the Web IDE. This component interfaces with a Singleton [Editor](https://gitlab.com/gitlab-org/gitlab/-/blob/862ad57c44ec758ef3942ac2e7a2bd40a37a9c59/app%2Fassets%2Fjavascripts%2Fide%2Flib%2Feditor.js#L21)
which manages some state for working with Monaco. Because of the Singleton nature of the Editor class,
the component `RepoEditor` is now forced to be a Singleton as well. Multiple instances of this component
would cause production issues because no one truly owns the instance of `Editor`.
diff --git a/doc/development/fe_guide/editor_lite.md b/doc/development/fe_guide/editor_lite.md
index 5ad0c753ced..f28588c23e9 100644
--- a/doc/development/fe_guide/editor_lite.md
+++ b/doc/development/fe_guide/editor_lite.md
@@ -15,6 +15,7 @@ GitLab features use it, including:
- [CI Linter](../../ci/lint.md)
- [Snippets](../../user/snippets.md)
- [Web Editor](../../user/project/repository/web_editor.md)
+- [Security Policies](../../user/application_security/threat_monitoring/index.md)
## How to use Editor Lite
diff --git a/doc/development/fe_guide/event_tracking.md b/doc/development/fe_guide/event_tracking.md
index e8b8e0c4885..3931f0b35ab 100644
--- a/doc/development/fe_guide/event_tracking.md
+++ b/doc/development/fe_guide/event_tracking.md
@@ -1,8 +1,9 @@
---
redirect_to: 'https://about.gitlab.com/handbook/product/product-intelligence-guide/'
+remove_date: '2021-12-01'
---
This document was moved to [another location](https://about.gitlab.com/handbook/product/product-intelligence-guide/).
-<!-- This redirect file can be deleted after December 1, 2021. -->
+<!-- This redirect file can be deleted after 2021-12-01. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
diff --git a/doc/development/fe_guide/frontend_faq.md b/doc/development/fe_guide/frontend_faq.md
index bf1dae6e7bd..6b9d5ace4e6 100644
--- a/doc/development/fe_guide/frontend_faq.md
+++ b/doc/development/fe_guide/frontend_faq.md
@@ -32,15 +32,15 @@ question:
document.body.dataset.page
```
-Find here the [source code setting the attribute](https://gitlab.com/gitlab-org/gitlab/blob/cc5095edfce2b4d4083a4fb1cdc7c0a1898b9921/app/views/layouts/application.html.haml#L4).
+Find here the [source code setting the attribute](https://gitlab.com/gitlab-org/gitlab/-/blob/cc5095edfce2b4d4083a4fb1cdc7c0a1898b9921/app/views/layouts/application.html.haml#L4).
#### Rails routes
-The `rake routes` command can be used to list all the routes available in the application. Piping the output into `grep`, we can perform a search through the list of available routes.
+The `rails routes` command can be used to list all the routes available in the application. Piping the output into `grep`, we can perform a search through the list of available routes.
The output includes the request types available, route parameters and the relevant controller.
```shell
-bundle exec rake routes | grep "issues"
+bundle exec rails routes | grep "issues"
```
### 2. `modal_copy_button` vs `clipboard_button`
@@ -82,7 +82,7 @@ follow up issue and attach it to the component implementation epic found in the
### 4. My submit form button becomes disabled after submitting
-A Submit button inside of a form attaches an `onSubmit` event listener on the form element. [This code](https://gitlab.com/gitlab-org/gitlab/blob/794c247a910e2759ce9b401356432a38a4535d49/app/assets/javascripts/main.js#L225) adds a `disabled` class selector to the submit button when the form is submitted. To avoid this behavior, add the class `js-no-auto-disable` to the button.
+A Submit button inside of a form attaches an `onSubmit` event listener on the form element. [This code](https://gitlab.com/gitlab-org/gitlab/-/blob/794c247a910e2759ce9b401356432a38a4535d49/app/assets/javascripts/main.js#L225) adds a `disabled` class selector to the submit button when the form is submitted. To avoid this behavior, add the class `js-no-auto-disable` to the button.
### 5. Should one use a full URL (for example `gon.gitlab_url`) or a full path (for example `gon.relative_url_root`) when referencing backend endpoints?
@@ -172,7 +172,7 @@ To return to the normal development mode:
### 8. Babel polyfills
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/28837) in GitLab 12.8.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/28837) in GitLab 12.8.
GitLab has enabled the Babel `preset-env` option
[`useBuiltIns: 'usage'`](https://babeljs.io/docs/en/babel-preset-env#usebuiltins-usage).
diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md
index 49c511c2b85..870605c82f4 100644
--- a/doc/development/fe_guide/graphql.md
+++ b/doc/development/fe_guide/graphql.md
@@ -94,7 +94,7 @@ their execution by clicking **Execute query** button on the top left:
## Apollo Client
To save duplicated clients getting created in different apps, we have a
-[default client](https://gitlab.com/gitlab-org/gitlab/blob/master/app/assets/javascripts/lib/graphql.js) that should be used. This sets up the
+[default client](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/lib/graphql.js) that should be used. This sets up the
Apollo client with the correct URL and also sets the CSRF headers.
Default client accepts two parameters: `resolvers` and `config`.
@@ -106,6 +106,12 @@ Default client accepts two parameters: `resolvers` and `config`.
- `assumeImmutableResults` (set to `false` by default) - this setting, when set to `true`, assumes that every single operation on updating Apollo Cache is immutable. It also sets `freezeResults` to `true`, so any attempt on mutating Apollo Cache throws a console warning in development environment. Please ensure you're following the immutability pattern on cache update operations before setting this option to `true`.
- `fetchPolicy` determines how you want your component to interact with the Apollo cache. Defaults to "cache-first".
+### Multiple client queries for the same object
+
+If you are make multiple queries to the same Apollo client object you might encounter the following error: "Store error: the application attempted to write an object with no provided ID but the store already contains an ID of SomeEntity". [This error only should occur when you have made a query with an ID field for a portion, then made another that returns what would be the same object, but is missing the ID field.](https://github.com/apollographql/apollo-client/issues/2510#issue-271829009)
+
+Please note this is being tracked in [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/326101) and the documentation will be updated when this issue is resolved.
+
## GraphQL Queries
To save query compilation at runtime, webpack can directly import `.graphql`
@@ -1091,7 +1097,7 @@ it('renders a loading state', () => {
const mockApollo = createMockApolloProvider();
const wrapper = createComponent({ mockApollo });
- expect(wrapper.find(LoadingSpinner).exists()).toBe(true)
+ expect(wrapper.findComponent(LoadingSpinner).exists()).toBe(true)
});
it('renders designs list', async () => {
@@ -1393,7 +1399,6 @@ describe('My Index test with `createMockApollo`', () => {
afterEach(() => {
wrapper.destroy();
- wrapper = null;
fetchLocalUserSpy = null;
});
diff --git a/doc/development/fe_guide/img/content_editor_highlevel_diagram.png b/doc/development/fe_guide/img/content_editor_highlevel_diagram.png
new file mode 100644
index 00000000000..73a71cf5843
--- /dev/null
+++ b/doc/development/fe_guide/img/content_editor_highlevel_diagram.png
Binary files differ
diff --git a/doc/development/fe_guide/index.md b/doc/development/fe_guide/index.md
index 0f3754c29e7..00f0d72571a 100644
--- a/doc/development/fe_guide/index.md
+++ b/doc/development/fe_guide/index.md
@@ -93,6 +93,11 @@ General information about frontend [dependencies](dependencies.md) and how we ma
How we implement [keyboard shortcuts](keyboard_shortcuts.md) that can be customized and disabled.
+## Editors
+
+GitLab text editing experiences are provided by the [Source Editor](editor_lite.md) and
+the [Content Editor](content_editor.md).
+
## Frontend FAQ
Read the [frontend's FAQ](frontend_faq.md) for common small pieces of helpful information.
diff --git a/doc/development/fe_guide/style/vue.md b/doc/development/fe_guide/style/vue.md
index 93e4f234ccb..5c79d47e7b0 100644
--- a/doc/development/fe_guide/style/vue.md
+++ b/doc/development/fe_guide/style/vue.md
@@ -463,7 +463,7 @@ Creating a global, mutable wrapper provides a number of advantages, including th
let wrapper;
// this can now be reused across tests
- const findMyComponent = wrapper.find(MyComponent);
+ const findMyComponent = wrapper.findComponent(MyComponent);
// ...
})
```
@@ -565,16 +565,15 @@ the mounting function (`mount` or `shallowMount`) to be used to mount the compon
function createComponent({ mountFn = shallowMount } = {}) { }
```
-1. Wrap calls to `mount` and `shallowMount` in `extendedWrapper`, this exposes `wrapper.findByTestId()`:
+1. Use the `mountExtended` and `shallowMountExtended` helpers to expose `wrapper.findByTestId()`:
```javascript
- import { shallowMount } from '@vue/test-utils';
- import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { SomeComponent } from 'components/some_component.vue';
let wrapper;
- const createWrapper = () => { wrapper = extendedWrapper(shallowMount(SomeComponent)); };
+ const createWrapper = () => { wrapper = shallowMountExtended(SomeComponent); };
const someButton = () => wrapper.findByTestId('someButtonTestId');
```
diff --git a/doc/development/fe_guide/troubleshooting.md b/doc/development/fe_guide/troubleshooting.md
index 1b3991ee80d..028184e0397 100644
--- a/doc/development/fe_guide/troubleshooting.md
+++ b/doc/development/fe_guide/troubleshooting.md
@@ -27,15 +27,15 @@ See [this video](https://youtu.be/-BkEhghP-kM) for an in-depth overview and inve
**Remedy - Try cloning the object that has Vue watchers**
```patch
-- expect(wrapper.find(ChildComponent).props()).toEqual(...);
-+ expect(cloneDeep(wrapper.find(ChildComponent).props())).toEqual(...)
+- expect(wrapper.findComponent(ChildComponent).props()).toEqual(...);
++ expect(cloneDeep(wrapper.findComponent(ChildComponent).props())).toEqual(...)
```
**Remedy - Try using `toMatchObject` instead of `toEqual`**
```patch
-- expect(wrapper.find(ChildComponent).props()).toEqual(...);
-+ expect(wrapper.find(ChildComponent).props()).toMatchObject(...);
+- expect(wrapper.findComponent(ChildComponent).props()).toEqual(...);
++ expect(wrapper.findComponent(ChildComponent).props()).toMatchObject(...);
```
Please note that `toMatchObject` actually changes the nature of the assertion and won't fail if some items are **missing** from the expectation.
diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md
index 1cce699218c..0a769f257d0 100644
--- a/doc/development/fe_guide/vue.md
+++ b/doc/development/fe_guide/vue.md
@@ -13,7 +13,7 @@ To get started with Vue, read through [their documentation](https://vuejs.org/v2
What is described in the following sections can be found in these examples:
- [Web IDE](https://gitlab.com/gitlab-org/gitlab-foss/tree/master/app/assets/javascripts/ide/stores)
-- [Security products](https://gitlab.com/gitlab-org/gitlab/tree/master/ee/app/assets/javascripts/vue_shared/security_reports)
+- [Security products](https://gitlab.com/gitlab-org/gitlab/-/tree/master/ee/app/assets/javascripts/vue_shared/security_reports)
- [Registry](https://gitlab.com/gitlab-org/gitlab-foss/tree/master/app/assets/javascripts/registry/stores)
## Vue architecture
@@ -323,17 +323,13 @@ testing the rendered output.
Here's an example of a well structured unit test for [this Vue component](#appendix---vue-component-subject-under-test):
```javascript
-import { shallowMount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { GlLoadingIcon } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import axios from '~/lib/utils/axios_utils';
import App from '~/todos/app.vue';
-const TEST_TODOS = [
- { text: 'Lorem ipsum test text' },
- { text: 'Lorem ipsum 2' },
-];
+const TEST_TODOS = [{ text: 'Lorem ipsum test text' }, { text: 'Lorem ipsum 2' }];
const TEST_NEW_TODO = 'New todo title';
const TEST_TODO_PATH = '/todos';
@@ -351,28 +347,27 @@ describe('~/todos/app.vue', () => {
afterEach(() => {
// IMPORTANT: Clean up the component instance and axios mock adapter
wrapper.destroy();
- wrapper = null;
-
mock.restore();
});
// It is very helpful to separate setting up the component from
// its collaborators (for example, Vuex and axios).
const createWrapper = (props = {}) => {
- wrapper = extendedWrapper(
- shallowMount(App, {
- propsData: {
- path: TEST_TODO_PATH,
- ...props,
- },
- })
- );
+ wrapper = shallowMountExtended(App, {
+ propsData: {
+ path: TEST_TODO_PATH,
+ ...props,
+ },
+ });
};
// Helper methods greatly help test maintainability and readability.
- const findLoader = () => wrapper.find(GlLoadingIcon);
+ const findLoader = () => wrapper.findComponent(GlLoadingIcon);
const findAddButton = () => wrapper.findByTestId('add-button');
const findTextInput = () => wrapper.findByTestId('text-input');
- const findTodoData = () => wrapper.findAll('[data-testid="todo-item"]').wrappers.map(wrapper => ({ text: wrapper.text() }));
+ const findTodoData = () =>
+ wrapper
+ .findAllByTestId('todo-item')
+ .wrappers.map((item) => ({ text: item.text() }));
describe('when mounted and loading', () => {
beforeEach(() => {
@@ -401,14 +396,13 @@ describe('~/todos/app.vue', () => {
expect(findTodoData()).toEqual(TEST_TODOS);
});
- it('when todo is added, should post new todo', () => {
- findTextInput().vm.$emit('update', TEST_NEW_TODO)
+ it('when todo is added, should post new todo', async () => {
+ findTextInput().vm.$emit('update', TEST_NEW_TODO);
findAddButton().vm.$emit('click');
- return wrapper.vm.$nextTick()
- .then(() => {
- expect(mock.history.post.map(x => JSON.parse(x.data))).toEqual([{ text: TEST_NEW_TODO }]);
- });
+ await wrapper.vm.$nextTick();
+
+ expect(mock.history.post.map((x) => JSON.parse(x.data))).toEqual([{ text: TEST_NEW_TODO }]);
});
});
});
diff --git a/doc/development/fe_guide/vuex.md b/doc/development/fe_guide/vuex.md
index d44ab64ae5d..3d0044928f1 100644
--- a/doc/development/fe_guide/vuex.md
+++ b/doc/development/fe_guide/vuex.md
@@ -40,7 +40,7 @@ When using Vuex at GitLab, separate these concerns into different files to impro
The following example shows an application that lists and adds users to the
state. (For a more complex example implementation, review the security
-applications stored in this [repository](https://gitlab.com/gitlab-org/gitlab/tree/master/ee/app/assets/javascripts/vue_shared/security_reports/store)).
+applications stored in this [repository](https://gitlab.com/gitlab-org/gitlab/-/tree/master/ee/app/assets/javascripts/vue_shared/security_reports/store)).
### `index.js`
@@ -464,7 +464,6 @@ describe('component', () => {
afterEach(() => {
wrapper.destroy();
- wrapper = null;
});
it('should show a user', async () => {