Commit 4be2bc9f authored by Andrew Fontaine's avatar Andrew Fontaine

Show environment alerts on new environment design

The alerts are nicely self-contained considering they already fetch the
environment alert via GraphQL.

Also update the tests to use the mock apollo provider instead of setting
the data manually, as we can do that now.
parent 9611e4fc
...@@ -40,6 +40,7 @@ export default { ...@@ -40,6 +40,7 @@ export default {
Terminal, Terminal,
TimeAgoTooltip, TimeAgoTooltip,
Delete, Delete,
EnvironmentAlert: () => import('ee_component/environments/components/environment_alert.vue'),
}, },
directives: { directives: {
GlTooltip, GlTooltip,
...@@ -97,6 +98,9 @@ export default { ...@@ -97,6 +98,9 @@ export default {
hasDeployment() { hasDeployment() {
return Boolean(this.environment?.upcomingDeployment || this.environment?.lastDeployment); return Boolean(this.environment?.upcomingDeployment || this.environment?.lastDeployment);
}, },
hasOpenedAlert() {
return this.environment?.hasOpenedAlert;
},
actions() { actions() {
if (!this.lastDeployment) { if (!this.lastDeployment) {
return []; return [];
...@@ -319,6 +323,9 @@ export default { ...@@ -319,6 +323,9 @@ export default {
class="gl-pl-4" class="gl-pl-4"
/> />
</div> </div>
<div v-if="hasOpenedAlert" class="gl-bg-gray-10 gl-md-px-7">
<environment-alert :environment="environment" class="gl-pl-4 gl-py-5" />
</div>
</gl-collapse> </gl-collapse>
</div> </div>
</template> </template>
...@@ -2,6 +2,9 @@ import VueApollo from 'vue-apollo'; ...@@ -2,6 +2,9 @@ import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql'; import createDefaultClient from '~/lib/graphql';
import environmentApp from './queries/environment_app.query.graphql'; import environmentApp from './queries/environment_app.query.graphql';
import pageInfoQuery from './queries/page_info.query.graphql'; import pageInfoQuery from './queries/page_info.query.graphql';
import environmentToDeleteQuery from './queries/environment_to_delete.query.graphql';
import environmentToRollbackQuery from './queries/environment_to_rollback.query.graphql';
import environmentToStopQuery from './queries/environment_to_stop.query.graphql';
import { resolvers } from './resolvers'; import { resolvers } from './resolvers';
import typeDefs from './typedefs.graphql'; import typeDefs from './typedefs.graphql';
...@@ -33,6 +36,52 @@ export const apolloProvider = (endpoint) => { ...@@ -33,6 +36,52 @@ export const apolloProvider = (endpoint) => {
}, },
}, },
}); });
cache.writeQuery({
query: environmentToDeleteQuery,
data: {
environmentToDelete: {
name: 'null',
__typename: 'LocalEnvironment',
id: '0',
deletePath: null,
folderPath: null,
retryUrl: null,
autoStopPath: null,
lastDeployment: null,
},
},
});
cache.writeQuery({
query: environmentToStopQuery,
data: {
environmentToStop: {
name: 'null',
__typename: 'LocalEnvironment',
id: '0',
deletePath: null,
folderPath: null,
retryUrl: null,
autoStopPath: null,
lastDeployment: null,
},
},
});
cache.writeQuery({
query: environmentToRollbackQuery,
data: {
environmentToRollback: {
name: 'null',
__typename: 'LocalEnvironment',
id: '0',
deletePath: null,
folderPath: null,
retryUrl: null,
autoStopPath: null,
lastDeployment: null,
},
},
});
return new VueApollo({ return new VueApollo({
defaultClient, defaultClient,
}); });
......
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import EnvironmentAlert from 'ee/environments/components/environment_alert.vue'; import EnvironmentAlert from 'ee/environments/components/environment_alert.vue';
import alertQuery from 'ee/environments/graphql/queries/environment.query.graphql';
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue'; import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
Vue.use(VueApollo);
describe('Environment Alert', () => { describe('Environment Alert', () => {
let wrapper; let wrapper;
let alertResolver;
const DEFAULT_PROVIDE = { projectPath: 'test-org/test' }; const DEFAULT_PROVIDE = { projectPath: 'test-org/test' };
const DEFAULT_PROPS = { environment: { name: 'staging' } }; const DEFAULT_PROPS = { environment: { name: 'staging' } };
const factory = (props = {}, provide = {}) => { const createApolloProvider = () => createMockApollo([[alertQuery, alertResolver]]);
const factory = async (props = {}, provide = {}) => {
const apolloProvider = createApolloProvider();
wrapper = mount(EnvironmentAlert, { wrapper = mount(EnvironmentAlert, {
apolloProvider,
propsData: { propsData: {
...DEFAULT_PROPS, ...DEFAULT_PROPS,
...props, ...props,
...@@ -18,12 +31,14 @@ describe('Environment Alert', () => { ...@@ -18,12 +31,14 @@ describe('Environment Alert', () => {
...provide, ...provide,
}, },
}); });
await waitForPromises();
}; };
const findSeverityBadge = () => wrapper.findComponent(SeverityBadge); const findSeverityBadge = () => wrapper.findComponent(SeverityBadge);
beforeEach(() => { beforeEach(() => {
factory(); alertResolver = jest.fn();
}); });
afterEach(() => { afterEach(() => {
...@@ -32,21 +47,29 @@ describe('Environment Alert', () => { ...@@ -32,21 +47,29 @@ describe('Environment Alert', () => {
}); });
describe('has alert', () => { describe('has alert', () => {
beforeEach(() => { beforeEach(async () => {
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details alertResolver.mockResolvedValue({
// eslint-disable-next-line no-restricted-syntax data: {
wrapper.setData({ project: {
alert: { id: '1',
environment: {
id: '2',
latestOpenedMostSevereAlert: {
severity: 'CRITICAL', severity: 'CRITICAL',
title: 'alert title', title: 'alert title',
prometheusAlert: { humanizedText: '>0.1% jest' }, prometheusAlert: { id: '3', humanizedText: '>0.1% jest' },
detailsUrl: '/alert/details', detailsUrl: '/alert/details',
startedAt: new Date(), startedAt: new Date(),
}, },
},
},
},
}); });
await factory();
}); });
it('should display the alert details', () => { it('should display the alert details', async () => {
const text = wrapper.text(); const text = wrapper.text();
expect(text).toContain('Critical'); expect(text).toContain('Critical');
expect(text).toContain('alert title >0.1% jest.'); expect(text).toContain('alert title >0.1% jest.');
...@@ -68,6 +91,21 @@ describe('Environment Alert', () => { ...@@ -68,6 +91,21 @@ describe('Environment Alert', () => {
}); });
describe('has no alert', () => { describe('has no alert', () => {
beforeEach(async () => {
alertResolver.mockResolvedValue({
data: {
project: {
id: '1',
environment: {
id: '2',
latestOpenedMostSevereAlert: null,
},
},
},
});
await factory();
});
it('should display nothing', () => { it('should display nothing', () => {
expect(wrapper.find('[data-testid="alert"]').exists()).toBe(false); expect(wrapper.find('[data-testid="alert"]').exists()).toBe(false);
expect(findSeverityBadge().exists()).toBe(false); expect(findSeverityBadge().exists()).toBe(false);
......
import VueApollo from 'vue-apollo';
import Vue, { nextTick } from 'vue';
import createMockApollo from 'helpers/mock_apollo_helper';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import { stubTransition } from 'helpers/stub_transition';
import EnvironmentItem from '~/environments/components/new_environment_item.vue';
import EnvironmentAlert from 'ee/environments/components/environment_alert.vue';
import alertQuery from 'ee/environments/graphql/queries/environment.query.graphql';
import { resolvedEnvironment } from 'jest/environments/graphql/mock_data';
Vue.use(VueApollo);
describe('~/environments/components/new_environment_item.vue', () => {
let wrapper;
let alert;
const createApolloProvider = () => {
return createMockApollo([
[
alertQuery,
jest.fn().mockResolvedValue({
data: {
project: {
id: '1',
environment: {
id: '2',
latestOpenedMostSevereAlert: {
severity: 'CRITICAL',
title: 'alert title',
prometheusAlert: { id: '3', humanizedText: '>0.1% jest' },
detailsUrl: '/alert/details',
startedAt: new Date(),
},
},
},
},
}),
],
]);
};
const createWrapper = async ({ propsData = {}, apolloProvider } = {}) => {
wrapper = mountExtended(EnvironmentItem, {
apolloProvider,
propsData: { environment: resolvedEnvironment, ...propsData },
provide: { helpPagePath: '/help' },
stubs: { transition: stubTransition() },
});
await nextTick();
alert = wrapper.findComponent(EnvironmentAlert);
};
it('shows an alert if one is opened', async () => {
const environment = { ...resolvedEnvironment, hasOpenedAlert: true };
await createWrapper({ propsData: { environment }, apolloProvider: createApolloProvider() });
expect(alert.exists()).toBe(true);
expect(alert.props('environment')).toBe(environment);
});
it('does not show an alert if one is opened', async () => {
await createWrapper({ apolloProvider: createApolloProvider() });
alert = wrapper.findComponent(EnvironmentAlert);
expect(alert.exists()).toBe(false);
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment