@@ -119,7 +119,8 @@ Please check this [rules](https://github.com/vuejs/eslint-plugin-vue#bulb-rules)
## Naming
1.**Extensions**: Use `.vue` extension for Vue components. Do not use `.js` as file extension ([#34371](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/34371)).
1.**Extensions**: Use `.vue` extension for Vue components. Do not use `.js` as file extension
1.**Reference Naming**: Use PascalCase for their instances:
```javascript
...
...
@@ -402,7 +403,8 @@ When using `v-for` you need to provide a *unique* `:key` attribute for each item
</div>
```
1. When using `v-for` with `template` and there is more than one child element, the `:key` values must be unique. It's advised to use `kebab-case` namespaces.
1. When using `v-for` with `template` and there is more than one child element, the `:key` values
must be unique. It's advised to use `kebab-case` namespaces.
```html
<templatev-for="(item, index) in items">
...
...
@@ -468,9 +470,10 @@ Useful links:
## Vue testing
Over time, a number of programming patterns and style preferences have emerged in our efforts to effectively test Vue components.
The following guide describes some of these. **These are not strict guidelines**, but rather a collection of suggestions and
good practices that aim to provide insight into how we write Vue tests at GitLab.
Over time, a number of programming patterns and style preferences have emerged in our efforts to
effectively test Vue components. The following guide describes some of these.
**These are not strict guidelines**, but rather a collection of suggestions and good practices that
aim to provide insight into how we write Vue tests at GitLab.
### Mounting a component
...
...
@@ -479,8 +482,10 @@ Typically, when testing a Vue component, the component should be "re-mounted" in
To achieve this:
1. Create a mutable `wrapper` variable inside the top-level `describe` block.
1. Mount the component using [`mount`](https://vue-test-utils.vuejs.org/api/#mount)/[`shallowMount`](https://vue-test-utils.vuejs.org/api/#shallowMount).
1. Reassign the resulting [`Wrapper`](https://vue-test-utils.vuejs.org/api/wrapper/#wrapper) instance to our `wrapper` variable.
1. Mount the component using [`mount`](https://vue-test-utils.vuejs.org/api/#mount)/
over [`expect.objectContaining`](https://jestjs.io/docs/en/expect#expectobjectcontainingobject):
```javascript
// good
...
...
@@ -664,12 +688,24 @@ Prefer `toMatchObject` over [`expect.objectContaining`](https://jestjs.io/docs/e
The goal of this accord is to make sure we are all on the same page.
1. When writing Vue, you may not use jQuery in your application.
1. If you need to grab data from the DOM, you may query the DOM 1 time while bootstrapping your application to grab data attributes using `dataset`. You can do this without jQuery.
1. If you need to grab data from the DOM, you may query the DOM 1 time while bootstrapping your
application to grab data attributes using `dataset`. You can do this without jQuery.
1. You may use a jQuery dependency in Vue.js following [this example from the docs](https://vuejs.org/v2/examples/select2.html).
1. If an outside jQuery Event needs to be listen to inside the Vue application, you may use jQuery event listeners.
1. We avoid adding new jQuery events when they are not required. Instead of adding new jQuery events take a look at [different methods to do the same task](https://vuejs.org/v2/api/#vm-emit).
1. You may query the `window` object one time, while bootstrapping your application for application specific data (e.g. `scrollTo` is ok to access anytime). Do this access during the bootstrapping of your application.
1. You may have a temporary but immediate need to create technical debt by writing code that does not follow our standards, to be refactored later. Maintainers need to be ok with the tech debt in the first place. An issue should be created for that tech debt to evaluate it further and discuss. In the coming months you should fix that tech debt, with its priority to be determined by maintainers.
1. When creating tech debt you must write the tests for that code before hand and those tests may not be rewritten. e.g. jQuery tests rewritten to Vue tests.
1. You may choose to use VueX as a centralized state management. If you choose not to use VueX, you must use the *store pattern* which can be found in the [Vue.js documentation](https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch).
1. Once you have chosen a centralized state-management solution you must use it for your entire application. i.e. Don't mix and match your state-management solutions.
1. If an outside jQuery Event needs to be listen to inside the Vue application, you may use
jQuery event listeners.
1. We avoid adding new jQuery events when they are not required. Instead of adding new jQuery
events take a look at [different methods to do the same task](https://vuejs.org/v2/api/#vm-emit).
1. You may query the `window` object one time, while bootstrapping your application for application
specific data (for example, `scrollTo` is ok to access anytime). Do this access during the
bootstrapping of your application.
1. You may have a temporary but immediate need to create technical debt by writing code that does
not follow our standards, to be refactored later. Maintainers need to be ok with the tech debt in
the first place. An issue should be created for that tech debt to evaluate it further and discuss.
In the coming months you should fix that tech debt, with its priority to be determined by maintainers.
1. When creating tech debt you must write the tests for that code before hand and those tests may
not be rewritten. For example, jQuery tests rewritten to Vue tests.
1. You may choose to use VueX as a centralized state management. If you choose not to use VueX, you
must use the *store pattern* which can be found in the
@@ -22,7 +22,8 @@ All new features built with Vue.js must follow a [Flux architecture](https://fac
The main goal we are trying to achieve is to have only one data flow and only one data entry.
In order to achieve this goal we use [vuex](#vuex).
You can also read about this architecture in Vue docs about [state management](https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch)
You can also read about this architecture in Vue docs about
and about [one way data flow](https://vuejs.org/v2/guide/components.html#One-Way-Data-Flow).
### Components and Store
...
...
@@ -62,14 +63,15 @@ Be sure to read about [page-specific JavaScript](performance.md#page-specific-ja
While mounting a Vue application, you might need to provide data from Rails to JavaScript.
To do that, you can use the `data` attributes in the HTML element and query them while mounting the application.
You should only do this while initializing the application, because the mounted element is replaced with a Vue-generated DOM.
You should only do this while initializing the application, because the mounted element is replaced
with a Vue-generated DOM.
The advantage of providing data from the DOM to the Vue instance through `props` in the `render`function
instead of querying the DOM inside the main Vue component is avoiding the need to create a fixture or an HTML element in the unit test,
which makes the tests easier.
The advantage of providing data from the DOM to the Vue instance through `props` in the `render`
function instead of querying the DOM inside the main Vue component is avoiding the need to create a
fixture or an HTML element in the unit test, which makes the tests easier.
See the following example, also, please refer to our [Vue style guide](style/vue.md#basic-rules) for additional
information on why we explicitly declare the data being passed into the Vue app;
See the following example, also, please refer to our [Vue style guide](style/vue.md#basic-rules) for
additional information on why we explicitly declare the data being passed into the Vue app;
```javascript
// haml
...
...
@@ -94,13 +96,15 @@ return new Vue({
});
```
> When adding an `id` attribute to mount a Vue application, please make sure this `id` is unique across the codebase
> When adding an `id` attribute to mount a Vue application, please make sure this `id` is unique
across the codebase.
#### Accessing the `gl` object
When we need to query the `gl` object for data that doesn't change during the application's life cycle, we should do it in the same place where we query the DOM.
By following this practice, we can avoid the need to mock the `gl` object, which makes tests easier.
It should be done while initializing our Vue instance, and the data should be provided as `props` to the main component:
When we need to query the `gl` object for data that doesn't change during the application's life
cycle, we should do it in the same place where we query the DOM. By following this practice, we can
avoid the need to mock the `gl` object, which makes tests easier. It should be done while
initializing our Vue instance, and the data should be provided as `props` to the main component:
```javascript
returnnewVue({
...
...
@@ -192,13 +196,18 @@ Check this [page](vuex.md) for more details.
In the [Vue documentation](https://vuejs.org/v2/api/#Options-Data) the Data function/object is defined as follows:
> The data object for the Vue instance. Vue recursively converts its properties into getter/setters to make it “reactive”. The object must be plain: native objects such as browser API objects and prototype properties are ignored. A rule of thumb is that data should just be data - it is not recommended to observe objects with their own stateful behavior.
> The data object for the Vue instance. Vue recursively converts its properties into getter/setters
to make it “reactive”. The object must be plain: native objects such as browser API objects and
prototype properties are ignored. A rule of thumb is that data should just be data - it is not
recommended to observe objects with their own stateful behavior.
Based on the Vue guidance:
-**Do not** use or create a JavaScript class in your [data function](https://vuejs.org/v2/api/#data), such as `user: new User()`.
-**Do not** use or create a JavaScript class in your [data function](https://vuejs.org/v2/api/#data),
such as `user: new User()`.
-**Do not** add new JavaScript class implementations.
-**Do** use [GraphQL](../api_graphql_styleguide.md), [Vuex](vuex.md) or a set of components if cannot use simple primitives or objects.
-**Do** use [GraphQL](../api_graphql_styleguide.md), [Vuex](vuex.md) or a set of components if
cannot use simple primitives or objects.
-**Do** maintain existing implementations using such approaches.
-**Do** Migrate components to a pure object model when there are substantial changes to it.
-**Do** add business logic to helpers or utils, so you can test them separately from your component.
...
...
@@ -209,7 +218,8 @@ There are additional reasons why having a JavaScript class presents maintainabil
- Once a class is created, it is easy to extend it in a way that can infringe Vue reactivity and best practices.
- A class adds a layer of abstraction, which makes the component API and its inner workings less clear.
- It makes it harder to test. Since the class is instantiated by the component data function, it is harder to 'manage' component and class separately.
- It makes it harder to test. Since the class is instantiated by the component data function, it is
harder to 'manage' component and class separately.
- Adding OOP to a functional codebase adds yet another way of writing code, reducing consistency and clarity.
## Style guide
...
...
@@ -231,6 +241,7 @@ Here's an example of a well structured unit test for [this Vue component](#appen
We should test for events emitted in response to an action within our component, this is useful to verify the correct events are being fired with the correct arguments.
We should test for events emitted in response to an action within our component, this is useful to
verify the correct events are being fired with the correct arguments.
For any DOM events we should use [`trigger`](https://vue-test-utils.vuejs.org/api/wrapper/#trigger) to fire out event.
For any DOM events we should use [`trigger`](https://vue-test-utils.vuejs.org/api/wrapper/#trigger)
@@ -342,7 +385,8 @@ it('should fire the click event', () => {
})
```
When we need to fire a Vue event, we should use [`emit`](https://vuejs.org/v2/guide/components-custom-events.html) to fire our event.
When we need to fire a Vue event, we should use [`emit`](https://vuejs.org/v2/guide/components-custom-events.html)
to fire our event.
```javascript
wrapper=shallowMount(DropdownItem);
...
...
@@ -355,7 +399,8 @@ it('should fire the itemClicked event', () => {
})
```
We should verify an event has been fired by asserting against the result of the [`emitted()`](https://vue-test-utils.vuejs.org/api/wrapper/#emitted) method
We should verify an event has been fired by asserting against the result of the