diff options
Diffstat (limited to 'doc/development/fe_guide')
-rw-r--r-- | doc/development/fe_guide/accessibility.md | 50 | ||||
-rw-r--r-- | doc/development/fe_guide/content_editor.md | 116 | ||||
-rw-r--r-- | doc/development/fe_guide/design_anti_patterns.md | 4 | ||||
-rw-r--r-- | doc/development/fe_guide/editor_lite.md | 1 | ||||
-rw-r--r-- | doc/development/fe_guide/event_tracking.md | 3 | ||||
-rw-r--r-- | doc/development/fe_guide/frontend_faq.md | 10 | ||||
-rw-r--r-- | doc/development/fe_guide/graphql.md | 11 | ||||
-rw-r--r-- | doc/development/fe_guide/img/content_editor_highlevel_diagram.png | bin | 0 -> 47794 bytes | |||
-rw-r--r-- | doc/development/fe_guide/index.md | 5 | ||||
-rw-r--r-- | doc/development/fe_guide/style/vue.md | 9 | ||||
-rw-r--r-- | doc/development/fe_guide/troubleshooting.md | 8 | ||||
-rw-r--r-- | doc/development/fe_guide/vue.md | 44 | ||||
-rw-r--r-- | doc/development/fe_guide/vuex.md | 3 |
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 Binary files differnew file mode 100644 index 00000000000..73a71cf5843 --- /dev/null +++ b/doc/development/fe_guide/img/content_editor_highlevel_diagram.png 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 () => { |