Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-11-10 06:10:31 +00:00
parent aaa0fba820
commit bef328bb8c
34 changed files with 189 additions and 84 deletions

View file

@ -55,12 +55,12 @@ export default {
return generateAgentRegistrationCommand(this.agentToken, this.kasAddress);
},
basicInstallPath() {
return helpPagePath('user/clusters/agent/index', {
return helpPagePath('user/clusters/agent/install/index', {
anchor: 'install-the-agent-into-the-cluster',
});
},
advancedInstallPath() {
return helpPagePath('user/clusters/agent/index', { anchor: 'advanced-installation' });
return helpPagePath('user/clusters/agent/install/index', { anchor: 'advanced-installation' });
},
},
methods: {

View file

@ -213,6 +213,7 @@ export default {
<div
v-if="hasRotateError"
class="gl-text-red-500 gl-display-flex gl-align-items-center gl-font-weight-normal gl-mb-3"
data-testid="rotate-error"
>
<gl-icon name="warning" class="gl-mr-2" />
<span>{{ $options.translations.instanceIdRegenerateError }}</span>

View file

@ -1,16 +1,17 @@
- name: "REST API Runner will not contain 'paused'"
- name: "REST API Runner will not contain `paused`"
announcement_milestone: "14.5" # The milestone when this feature was first announced as deprecated.
removal_milestone: "15.0" # the milestone when this feature is planned to be removed
body: | # Do not modify this line, instead modify the lines below.
Runner REST API will not return "paused" as a status in GitLab 15.0.
Runner REST API will not return `paused` as a status in GitLab 15.0.
REST API: Paused runners' status will only relate to runner contact status, such as:
"online", "offline", "not_connected". Status "paused" will not appear when the runner is
Paused runners' status will only relate to runner contact status, such as:
`online`, `offline`, or `not_connected`. Status `paused` will not appear when the runner is
not active.
When checking if a runner is "paused", API users are advised to check the boolean attribute
"active" to be `false` instead.
When checking if a runner is `paused`, API users are advised to check the boolean attribute
`active` to be `false` instead.
stage: Verify
tiers: [Core, Premium, Ultimate]
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/344648
documentation_url: https://docs.gitlab.com/ee/api/runners.html
announcement_date: "2021-11-22"

View file

@ -450,6 +450,78 @@ The conventional Secure [analyzer](https://gitlab.com/gitlab-org/security-produc
If the scanner report is small, less than 35 lines, then feel free to [inline the report](https://gitlab.com/gitlab-org/security-products/analyzers/sobelow/-/blob/8bd2428a/convert/convert_test.go#L13-77) rather than use a `testdata` directory.
#### Test Diffs
The [go-cmp]<https://github.com/google/go-cmp> package should be used when comparing large structs in tests. It makes it possible to output a specific diff where the two structs differ, rather than seeing the whole of both structs printed out in the test logs. Here is a small example:
```golang
package main
import (
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
)
type Foo struct {
Desc Bar
Point Baz
}
type Bar struct {
A string
B string
}
type Baz struct {
X int
Y int
}
func TestHelloWorld(t *testing.T) {
want := Foo{
Desc: Bar{A: "a", B: "b"},
Point: Baz{X: 1, Y: 2},
}
got := Foo{
Desc: Bar{A: "a", B: "b"},
Point: Baz{X: 2, Y: 2},
}
t.Log("reflect comparison:")
if !reflect.DeepEqual(got, want) {
t.Errorf("Wrong result. want:\n%v\nGot:\n%v", want, got)
}
t.Log("cmp comparison:")
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("Wrong result. (-want +got):\n%s", diff)
}
}
```
The output demonstrates why `go-cmp` is far superior when comparing large structs. Even though you could spot the difference with this small difference, it quickly gets unwieldy as the data grows.
```plaintext
main_test.go:36: reflect comparison:
main_test.go:38: Wrong result. want:
{{a b} {1 2}}
Got:
{{a b} {2 2}}
main_test.go:41: cmp comparison:
main_test.go:43: Wrong result. (-want +got):
main.Foo{
Desc: {A: "a", B: "b"},
Point: main.Baz{
- X: 1,
+ X: 2,
Y: 2,
},
}
```
---
[Return to Development documentation](../index.md).

View file

@ -94,18 +94,18 @@ Note that we are not deprecating the Kerberos SPNEGO integration, only the old p
Announced: 2021-09-22
### REST API Runner will not contain 'paused'
### REST API Runner will not contain `paused`
Runner REST API will not return "paused" as a status in GitLab 15.0.
Runner REST API will not return `paused` as a status in GitLab 15.0.
REST API: Paused runners' status will only relate to runner contact status, such as:
"online", "offline", "not_connected". Status "paused" will not appear when the runner is
Paused runners' status will only relate to runner contact status, such as:
`online`, `offline`, or `not_connected`. Status `paused` will not appear when the runner is
not active.
When checking if a runner is "paused", API users are advised to check the boolean attribute
"active" to be `false` instead.
When checking if a runner is `paused`, API users are advised to check the boolean attribute
`active` to be `false` instead.
Announced:
Announced: 2021-11-22
### `AuthenticationType` for `[runners.cache.s3]` must be explicitly assigned

View file

@ -1175,6 +1175,19 @@ For more information, see [Offline environments](../offline_deployments/index.md
## Troubleshooting
### Error waiting for API Security 'http://127.0.0.1:5000' to become available
A bug exists in versions of the API Fuzzing analyzer prior to v1.6.196 that can cause a background process to fail under certain conditions. The solution is to update to a newer version of the DAST API analyzer.
The version information can be found in the job details for the `apifuzzer_fuzz` job.
If the issue is occuring with versions v1.6.196 or greater, please contact Support and provide the following information:
1. Reference this troubleshooting section and ask for the issue to be escalated to the Dynamic Analysis Team.
1. The full console output of the job.
1. The `gl-api-security-scanner.log` file available as a job artifact. In the right-hand panel of the job details page, select the **Browse** button.
1. The `apifuzzer_fuzz` job definition from your `.gitlab-ci.yml` file.
### Error, the OpenAPI document is not valid. Errors were found during validation of the document using the published OpenAPI schema
At the start of an API Fuzzing job the OpenAPI Specification is validated against the [published schema](https://github.com/OAI/OpenAPI-Specification/tree/master/schemas). This error is shown when the provided OpenAPI Specification has validation errors. Errors can be introduced when creating an OpenAPI Specification manually, and also when the schema is generated.

View file

@ -1132,6 +1132,19 @@ For more information, see [Offline environments](../offline_deployments/index.md
## Troubleshooting
### Error waiting for API Security 'http://127.0.0.1:5000' to become available
A bug exists in versions of the DAST API analyzer prior to v1.6.196 that can cause a background process to fail under certain conditions. The solution is to update to a newer version of the DAST API analyzer.
The version information can be found in the job details for the `dast_api` job.
If the issue is occuring with versions v1.6.196 or greater, please contact Support and provide the following information:
1. Reference this troubleshooting section and ask for the issue to be escalated to the Dynamic Analysis Team.
1. The full console output of the job.
1. The `gl-api-security-scanner.log` file available as a job artifact. In the right-hand panel of the job details page, select the **Browse** button.
1. The `dast_api` job definition from your `.gitlab-ci.yml` file.
### Failed to start scanner session (version header not found)
The DAST API engine outputs an error message when it cannot establish a connection with the scanner application component. The error message is shown in the job output window of the `dast_api` job. A common cause of this issue is changing the `DAST_API_API` variable from its default.

View file

@ -201,8 +201,7 @@ To prevent a merge request introducing a security vulnerability in a project, en
Vulnerability-Check rule. While this rule is enabled, an additional merge request approval is
required when the latest security report in a merge request:
- Contains vulnerabilities that are not present in the target branch. Note that approval is still
required for dismissed vulnerabilities.
- Contains vulnerabilities with states (for example, `previously detected`, `dismissed`) matching the rule's vulnerability states. Only `newly detected` will be considered if the target branch differs from the project default branch.
- Contains vulnerabilities with severity levels (for example, `high`, `critical`, or `unknown`)
matching the rule's severity levels.
- Contains a vulnerability count higher than the rule allows.
@ -210,7 +209,7 @@ required when the latest security report in a merge request:
An approval is optional when the security report:
- Contains no new vulnerabilities when compared to the target branch.
- Contains only vulnerabilities with states (for example, `newly detected`, `resolved`) **NOT** matching the rule's vulnerability states.
- Contains only vulnerabilities with severity levels (for example, `low`, `medium`) **NOT** matching
the rule's severity levels.
- Contains a vulnerability count equal to or less than what the rule allows.

View file

@ -26,12 +26,12 @@ describe('Alert Handler', () => {
});
it('should render the alert', () => {
expect(findFirstAlert()).toExist();
expect(findFirstAlert()).not.toBe(null);
});
it('should dismiss the alert on click', () => {
findFirstDismissButton().click();
expect(findFirstAlert()).not.toExist();
expect(findFirstAlert()).toBe(null);
});
});
@ -58,12 +58,12 @@ describe('Alert Handler', () => {
});
it('should render the banner', () => {
expect(findFirstBanner()).toExist();
expect(findFirstBanner()).not.toBe(null);
});
it('should dismiss the banner on click', () => {
findFirstDismissButton().click();
expect(findFirstBanner()).not.toExist();
expect(findFirstBanner()).toBe(null);
});
});
@ -79,12 +79,12 @@ describe('Alert Handler', () => {
});
it('should render the banner', () => {
expect(findFirstAlert()).toExist();
expect(findFirstAlert()).not.toBe(null);
});
it('should dismiss the banner on click', () => {
findFirstDismissButtonByClass().click();
expect(findFirstAlert()).not.toExist();
expect(findFirstAlert()).toBe(null);
});
});
});

View file

@ -72,7 +72,7 @@ describe('ConfirmModal', () => {
it('starts with only JsHooks', () => {
expect(findJsHooks()).toHaveLength(buttons.length);
expect(findModal()).not.toExist();
expect(findModal()).toBe(null);
});
describe('when button clicked', () => {
@ -87,7 +87,7 @@ describe('ConfirmModal', () => {
describe('GlModal', () => {
it('is rendered', () => {
expect(findModal()).toExist();
expect(findModal()).not.toBe(null);
expect(modalIsHidden()).toBe(false);
});

View file

@ -40,7 +40,7 @@ describe('DeleteLabelModal', () => {
it('starts with only js-containers', () => {
expect(findJsHooks()).toHaveLength(buttons.length);
expect(findModal()).not.toExist();
expect(findModal()).toBe(null);
});
describe('when first button clicked', () => {
@ -54,7 +54,7 @@ describe('DeleteLabelModal', () => {
});
it('renders GlModal', () => {
expect(findModal()).toExist();
expect(findModal()).not.toBe(null);
});
});

View file

@ -50,20 +50,20 @@ describe('Deploy keys key', () => {
it('shows pencil button for editing', () => {
createComponent({ deployKey });
expect(wrapper.find('.btn [data-testid="pencil-icon"]')).toExist();
expect(wrapper.find('.btn [data-testid="pencil-icon"]').exists()).toBe(true);
});
it('shows disable button when the project is not deletable', () => {
createComponent({ deployKey });
expect(wrapper.find('.btn [data-testid="cancel-icon"]')).toExist();
expect(wrapper.find('.btn [data-testid="cancel-icon"]').exists()).toBe(true);
});
it('shows remove button when the project is deletable', () => {
createComponent({
deployKey: { ...deployKey, destroyed_when_orphaned: true, almost_orphaned: true },
});
expect(wrapper.find('.btn [data-testid="remove-icon"]')).toExist();
expect(wrapper.find('.btn [data-testid="remove-icon"]').exists()).toBe(true);
});
});
@ -137,7 +137,7 @@ describe('Deploy keys key', () => {
it('shows pencil button for editing', () => {
createComponent({ deployKey });
expect(wrapper.find('.btn [data-testid="pencil-icon"]')).toExist();
expect(wrapper.find('.btn [data-testid="pencil-icon"]').exists()).toBe(true);
});
it('shows disable button when key is enabled', () => {
@ -145,7 +145,7 @@ describe('Deploy keys key', () => {
createComponent({ deployKey });
expect(wrapper.find('.btn [data-testid="cancel-icon"]')).toExist();
expect(wrapper.find('.btn [data-testid="cancel-icon"]').exists()).toBe(true);
});
});
});

View file

@ -37,7 +37,7 @@ describe('Deploy keys panel', () => {
mountComponent();
const tableHeader = findTableRowHeader();
expect(tableHeader).toExist();
expect(tableHeader.exists()).toBe(true);
expect(tableHeader.text()).toContain('Deploy key');
expect(tableHeader.text()).toContain('Project usage');
expect(tableHeader.text()).toContain('Created');

View file

@ -87,7 +87,7 @@ describe('Design management list item component', () => {
describe('before image is loaded', () => {
it('renders loading spinner', () => {
expect(wrapper.find(GlLoadingIcon)).toExist();
expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
});
});

View file

@ -1,5 +1,6 @@
import { GlModal, GlSprintf, GlAlert } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import Component from '~/feature_flags/components/configure_feature_flags_modal.vue';
describe('Configure Feature Flags Modal', () => {
@ -20,7 +21,7 @@ describe('Configure Feature Flags Modal', () => {
};
let wrapper;
const factory = (props = {}, { mountFn = shallowMount, ...options } = {}) => {
const factory = (props = {}, { mountFn = shallowMountExtended, ...options } = {}) => {
wrapper = mountFn(Component, {
provide,
stubs: { GlSprintf },
@ -140,11 +141,13 @@ describe('Configure Feature Flags Modal', () => {
describe('has rotate error', () => {
afterEach(() => wrapper.destroy());
beforeEach(factory.bind(null, { hasRotateError: false }));
beforeEach(() => {
factory({ hasRotateError: true });
});
it('should display an error', async () => {
expect(wrapper.find('.text-danger')).toExist();
expect(wrapper.find('[name="warning"]')).toExist();
expect(wrapper.findByTestId('rotate-error').exists()).toBe(true);
expect(wrapper.find('[name="warning"]').exists()).toBe(true);
});
});

View file

@ -198,7 +198,7 @@ describe('InviteMembersModal', () => {
describe('rendering the access expiration date field', () => {
it('renders the datepicker', () => {
expect(findDatepicker()).toExist();
expect(findDatepicker().exists()).toBe(true);
});
});
});

View file

@ -1,7 +1,8 @@
import { GlButton, GlModal } from '@gitlab/ui';
import { GlModal } from '@gitlab/ui';
import { stubComponent } from 'helpers/stub_component';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import CsvImportModal from '~/issuable/components/csv_import_modal.vue';
import { __ } from '~/locale';
jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
@ -36,7 +37,6 @@ describe('CsvImportModal', () => {
});
const findModal = () => wrapper.findComponent(GlModal);
const findPrimaryButton = () => wrapper.findComponent(GlButton);
const findForm = () => wrapper.find('form');
const findFileInput = () => wrapper.findByLabelText('Upload CSV file');
const findAuthenticityToken = () => new FormData(findForm().element).get('authenticity_token');
@ -64,11 +64,11 @@ describe('CsvImportModal', () => {
expect(findForm().exists()).toBe(true);
expect(findForm().attributes('action')).toBe(importCsvIssuesPath);
expect(findAuthenticityToken()).toBe('mock-csrf-token');
expect(findFileInput()).toExist();
expect(findFileInput().exists()).toBe(true);
});
it('displays the correct primary button action text', () => {
expect(findPrimaryButton()).toExist();
expect(findModal().props('actionPrimary')).toEqual({ text: __('Import issues') });
});
it('submits the form when the primary action is clicked', () => {

View file

@ -456,7 +456,7 @@ describe('Dashboard', () => {
it('shows the links section', () => {
expect(wrapper.vm.shouldShowLinksSection).toBe(true);
expect(wrapper.find(LinksSection)).toExist();
expect(wrapper.findComponent(LinksSection).exists()).toBe(true);
});
});

View file

@ -1,5 +1,7 @@
import { GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import LinksSection from '~/monitoring/components/links_section.vue';
import { createStore } from '~/monitoring/stores';
@ -26,12 +28,12 @@ describe('Links Section component', () => {
createShallowWrapper();
});
it('does not render a section if no links are present', () => {
it('does not render a section if no links are present', async () => {
setState();
return wrapper.vm.$nextTick(() => {
expect(findLinks()).not.toExist();
});
await nextTick();
expect(findLinks().length).toBe(0);
});
it('renders a link inside a section', () => {

View file

@ -15,12 +15,12 @@ describe('Text variable component', () => {
});
};
const findInput = () => wrapper.find(GlFormInput);
const findInput = () => wrapper.findComponent(GlFormInput);
it('renders a text input when all props are passed', () => {
createShallowWrapper();
expect(findInput()).toExist();
expect(findInput().exists()).toBe(true);
});
it('always has a default value', () => {

View file

@ -29,7 +29,7 @@ describe('monitoring/pages/dashboard_page', () => {
});
};
const findDashboardComponent = () => wrapper.find(Dashboard);
const findDashboardComponent = () => wrapper.findComponent(Dashboard);
beforeEach(() => {
buildRouter();
@ -60,7 +60,7 @@ describe('monitoring/pages/dashboard_page', () => {
smallEmptyState: false,
};
expect(findDashboardComponent()).toExist();
expect(findDashboardComponent().exists()).toBe(true);
expect(allProps).toMatchObject(findDashboardComponent().props());
});
});

View file

@ -58,7 +58,6 @@ describe('issue_note_body component', () => {
it('adds autosave', () => {
const autosaveKey = `autosave/Note/${note.noteable_type}/${note.id}`;
expect(vm.autosave).toExist();
expect(vm.autosave.key).toEqual(autosaveKey);
});
});

View file

@ -33,12 +33,12 @@ describe('InstallationCommands', () => {
});
}
const npmInstallation = () => wrapper.find(NpmInstallation);
const mavenInstallation = () => wrapper.find(MavenInstallation);
const conanInstallation = () => wrapper.find(ConanInstallation);
const nugetInstallation = () => wrapper.find(NugetInstallation);
const pypiInstallation = () => wrapper.find(PypiInstallation);
const composerInstallation = () => wrapper.find(ComposerInstallation);
const npmInstallation = () => wrapper.findComponent(NpmInstallation);
const mavenInstallation = () => wrapper.findComponent(MavenInstallation);
const conanInstallation = () => wrapper.findComponent(ConanInstallation);
const nugetInstallation = () => wrapper.findComponent(NugetInstallation);
const pypiInstallation = () => wrapper.findComponent(PypiInstallation);
const composerInstallation = () => wrapper.findComponent(ComposerInstallation);
afterEach(() => {
wrapper.destroy();
@ -57,7 +57,7 @@ describe('InstallationCommands', () => {
it(`${packageEntity.packageType} instructions exist`, () => {
createComponent({ packageEntity });
expect(selector()).toExist();
expect(selector().exists()).toBe(true);
});
});
});

View file

@ -38,7 +38,7 @@ describe('Dropdown select component', () => {
it('creates a hidden input if fieldName is provided', () => {
mountDropdown({ fieldName: 'namespace-input' });
expect(findNamespaceInput()).toExist();
expect(findNamespaceInput().exists()).toBe(true);
expect(findNamespaceInput().attributes('name')).toBe('namespace-input');
});
@ -57,9 +57,9 @@ describe('Dropdown select component', () => {
// wait for dropdown options to populate
await wrapper.vm.$nextTick();
expect(findDropdownOption('user: Administrator')).toExist();
expect(findDropdownOption('group: GitLab Org')).toExist();
expect(findDropdownOption('group: Foobar')).not.toExist();
expect(findDropdownOption('user: Administrator').exists()).toBe(true);
expect(findDropdownOption('group: GitLab Org').exists()).toBe(true);
expect(findDropdownOption('group: Foobar').exists()).toBe(false);
findDropdownOption('user: Administrator').trigger('click');
await wrapper.vm.$nextTick();

View file

@ -35,7 +35,7 @@ describe('Pipelines Empty State', () => {
});
it('should render the CI/CD templates', () => {
expect(pipelinesCiTemplates()).toExist();
expect(pipelinesCiTemplates().exists()).toBe(true);
});
});

View file

@ -554,7 +554,7 @@ describe('Pipelines', () => {
});
it('renders the CI/CD templates', () => {
expect(wrapper.find(PipelinesCiTemplates)).toExist();
expect(wrapper.findComponent(PipelinesCiTemplates).exists()).toBe(true);
});
describe('when the code_quality_walkthrough experiment is active', () => {
@ -568,7 +568,7 @@ describe('Pipelines', () => {
});
it('renders the CI/CD templates', () => {
expect(wrapper.find(PipelinesCiTemplates)).toExist();
expect(wrapper.findComponent(PipelinesCiTemplates).exists()).toBe(true);
});
});
@ -597,7 +597,7 @@ describe('Pipelines', () => {
});
it('renders the CI/CD templates', () => {
expect(wrapper.find(PipelinesCiTemplates)).toExist();
expect(wrapper.findComponent(PipelinesCiTemplates).exists()).toBe(true);
});
});

View file

@ -115,7 +115,7 @@ describe('Author Select', () => {
});
it('does not have popover text by default', () => {
expect(wrapper.attributes('title')).not.toExist();
expect(wrapper.attributes('title')).toBeUndefined();
});
});

View file

@ -134,12 +134,12 @@ describe('App component', () => {
it('renders main-heading with correct text', () => {
const mainHeading = findMainHeading();
expect(mainHeading).toExist();
expect(mainHeading.exists()).toBe(true);
expect(mainHeading.text()).toContain('Security Configuration');
});
it('renders GlTab Component ', () => {
expect(findTab()).toExist();
expect(findTab().exists()).toBe(true);
});
it('renders right amount of tabs with correct title ', () => {

View file

@ -50,7 +50,7 @@ describe('Issuable Time Tracking Report', () => {
it('should render loading spinner', () => {
mountComponent();
expect(findLoadingIcon()).toExist();
expect(findLoadingIcon().exists()).toBe(true);
});
it('should render error message on reject', async () => {

View file

@ -47,10 +47,12 @@ Object.assign(global, {
setFixtures: setHTMLFixture,
});
const JQUERY_MATCHERS_TO_EXCLUDE = ['toHaveLength', 'toExist'];
// custom-jquery-matchers was written for an old Jest version, we need to make it compatible
Object.entries(jqueryMatchers).forEach(([matcherName, matcherFactory]) => {
// Don't override existing Jest matcher
if (matcherName === 'toHaveLength') {
// Exclude these jQuery matchers
if (JQUERY_MATCHERS_TO_EXCLUDE.includes(matcherName)) {
return;
}

View file

@ -191,7 +191,7 @@ describe('MRWidgetMerged', () => {
});
it('shows button to copy commit SHA to clipboard', () => {
expect(selectors.copyMergeShaButton).toExist();
expect(selectors.copyMergeShaButton).not.toBe(null);
expect(selectors.copyMergeShaButton.getAttribute('data-clipboard-text')).toBe(
vm.mr.mergeCommitSha,
);
@ -201,14 +201,14 @@ describe('MRWidgetMerged', () => {
vm.mr.mergeCommitSha = null;
Vue.nextTick(() => {
expect(selectors.copyMergeShaButton).not.toExist();
expect(selectors.copyMergeShaButton).toBe(null);
expect(vm.$el.querySelector('.mr-info-list').innerText).not.toContain('with');
done();
});
});
it('shows merge commit SHA link', () => {
expect(selectors.mergeCommitShaLink).toExist();
expect(selectors.mergeCommitShaLink).not.toBe(null);
expect(selectors.mergeCommitShaLink.text).toContain(vm.mr.shortMergeCommitSha);
expect(selectors.mergeCommitShaLink.href).toBe(vm.mr.mergeCommitPath);
});

View file

@ -16,6 +16,6 @@ describe('ContentViewer', () => {
propsData: { path, fileSize: 1024, type },
});
expect(wrapper.find(selector).element).toExist();
expect(wrapper.find(selector).exists()).toBe(true);
});
});

View file

@ -42,7 +42,7 @@ describe('MarkdownViewer', () => {
it('renders an animation container while the markdown is loading', () => {
createComponent();
expect(wrapper.find('.animation-container')).toExist();
expect(wrapper.find('.animation-container').exists()).toBe(true);
});
it('renders markdown preview preview renders and loads rendered markdown from server', () => {

View file

@ -29,7 +29,7 @@ describe('~/whats_new/utils/notification', () => {
subject();
expect(findNotificationCountEl()).toExist();
expect(findNotificationCountEl()).not.toBe(null);
expect(notificationEl.classList).toContain('with-notifications');
});
@ -38,11 +38,11 @@ describe('~/whats_new/utils/notification', () => {
notificationEl.classList.add('with-notifications');
localStorage.setItem('display-whats-new-notification', 'version-digest');
expect(findNotificationCountEl()).toExist();
expect(findNotificationCountEl()).not.toBe(null);
subject();
expect(findNotificationCountEl()).not.toExist();
expect(findNotificationCountEl()).toBe(null);
expect(notificationEl.classList).not.toContain('with-notifications');
});
});