Commit de861e89 authored by Miguel Rincon's avatar Miguel Rincon

Load runner webUrl from GraphQL

This change removes technical debt by loading the "webUrl"
of a runner from the API instead of hardcoding it.

The Runner link will vary for the admin and the group users
respectively.
parent 93aeeb73
<script> <script>
import { GlLink } from '@gitlab/ui';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { fetchPolicies } from '~/lib/graphql'; import { fetchPolicies } from '~/lib/graphql';
import { updateHistory } from '~/lib/utils/url_utility'; import { updateHistory } from '~/lib/utils/url_utility';
...@@ -6,6 +7,7 @@ import { formatNumber, sprintf, __ } from '~/locale'; ...@@ -6,6 +7,7 @@ import { formatNumber, sprintf, __ } from '~/locale';
import RunnerFilteredSearchBar from '../components/runner_filtered_search_bar.vue'; import RunnerFilteredSearchBar from '../components/runner_filtered_search_bar.vue';
import RunnerList from '../components/runner_list.vue'; import RunnerList from '../components/runner_list.vue';
import RunnerManualSetupHelp from '../components/runner_manual_setup_help.vue'; import RunnerManualSetupHelp from '../components/runner_manual_setup_help.vue';
import RunnerName from '../components/runner_name.vue';
import RunnerPagination from '../components/runner_pagination.vue'; import RunnerPagination from '../components/runner_pagination.vue';
import RunnerTypeHelp from '../components/runner_type_help.vue'; import RunnerTypeHelp from '../components/runner_type_help.vue';
import { statusTokenConfig } from '../components/search_tokens/status_token_config'; import { statusTokenConfig } from '../components/search_tokens/status_token_config';
...@@ -23,10 +25,12 @@ import { captureException } from '../sentry_utils'; ...@@ -23,10 +25,12 @@ import { captureException } from '../sentry_utils';
export default { export default {
name: 'AdminRunnersApp', name: 'AdminRunnersApp',
components: { components: {
GlLink,
RunnerFilteredSearchBar, RunnerFilteredSearchBar,
RunnerList, RunnerList,
RunnerManualSetupHelp, RunnerManualSetupHelp,
RunnerTypeHelp, RunnerTypeHelp,
RunnerName,
RunnerPagination, RunnerPagination,
}, },
props: { props: {
...@@ -150,7 +154,13 @@ export default { ...@@ -150,7 +154,13 @@ export default {
{{ __('No runners found') }} {{ __('No runners found') }}
</div> </div>
<template v-else> <template v-else>
<runner-list :runners="runners.items" :loading="runnersLoading" /> <runner-list :runners="runners.items" :loading="runnersLoading">
<template #runner-name="{ runner }">
<gl-link :href="runner.adminUrl">
<runner-name :runner="runner" />
</gl-link>
</template>
</runner-list>
<runner-pagination v-model="search.pagination" :page-info="runners.pageInfo" /> <runner-pagination v-model="search.pagination" :page-info="runners.pageInfo" />
</template> </template>
</div> </div>
......
<script> <script>
import { GlButton, GlButtonGroup, GlTooltipDirective } from '@gitlab/ui'; import { GlButton, GlButtonGroup, GlTooltipDirective } from '@gitlab/ui';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { __, s__ } from '~/locale'; import { __, s__ } from '~/locale';
import runnerDeleteMutation from '~/runner/graphql/runner_delete.mutation.graphql'; import runnerDeleteMutation from '~/runner/graphql/runner_delete.mutation.graphql';
import runnerUpdateMutation from '~/runner/graphql/runner_update.mutation.graphql'; import runnerUpdateMutation from '~/runner/graphql/runner_update.mutation.graphql';
...@@ -37,13 +36,6 @@ export default { ...@@ -37,13 +36,6 @@ export default {
}; };
}, },
computed: { computed: {
runnerNumericalId() {
return getIdFromGraphQLId(this.runner.id);
},
runnerUrl() {
// TODO implement using webUrl from the API
return `${gon.gitlab_url || ''}/admin/runners/${this.runnerNumericalId}`;
},
isActive() { isActive() {
return this.runner.active; return this.runner.active;
}, },
...@@ -119,7 +111,7 @@ export default { ...@@ -119,7 +111,7 @@ export default {
}, },
}, },
awaitRefetchQueries: true, awaitRefetchQueries: true,
refetchQueries: ['getRunners'], refetchQueries: ['getRunners', 'getGroupRunners'],
}); });
if (errors && errors.length) { if (errors && errors.length) {
throw new Error(errors.join(' ')); throw new Error(errors.join(' '));
...@@ -147,12 +139,20 @@ export default { ...@@ -147,12 +139,20 @@ export default {
<template> <template>
<gl-button-group> <gl-button-group>
<!--
This button appears for administratos: those with
access to the adminUrl. More advanced permissions policies
will allow more granular permissions.
See https://gitlab.com/gitlab-org/gitlab/-/issues/334802
-->
<gl-button <gl-button
v-if="runner.adminUrl"
v-gl-tooltip.hover.viewport v-gl-tooltip.hover.viewport
:href="runner.adminUrl"
:title="$options.i18n.I18N_EDIT" :title="$options.i18n.I18N_EDIT"
:aria-label="$options.i18n.I18N_EDIT" :aria-label="$options.i18n.I18N_EDIT"
icon="pencil" icon="pencil"
:href="runnerUrl"
data-testid="edit-runner" data-testid="edit-runner"
/> />
<gl-button <gl-button
......
<script> <script>
import { GlLink } from '@gitlab/ui';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue'; import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
import RunnerName from '../runner_name.vue';
export default { export default {
components: { components: {
GlLink,
TooltipOnTruncate, TooltipOnTruncate,
RunnerName,
}, },
props: { props: {
runner: { runner: {
...@@ -15,26 +14,18 @@ export default { ...@@ -15,26 +14,18 @@ export default {
}, },
}, },
computed: { computed: {
runnerNumericalId() {
return getIdFromGraphQLId(this.runner.id);
},
runnerUrl() {
// TODO implement using webUrl from the API
return `${gon.gitlab_url || ''}/admin/runners/${this.runnerNumericalId}`;
},
description() { description() {
return this.runner.description; return this.runner.description;
}, },
shortSha() {
return this.runner.shortSha;
},
}, },
}; };
</script> </script>
<template> <template>
<div> <div>
<gl-link :href="runnerUrl"> #{{ runnerNumericalId }} ({{ shortSha }})</gl-link> <slot :runner="runner" name="runner-name">
<runner-name :runner="runner" />
</slot>
<tooltip-on-truncate class="gl-display-block" :title="description" truncate-target="child"> <tooltip-on-truncate class="gl-display-block" :title="description" truncate-target="child">
<div class="gl-text-truncate"> <div class="gl-text-truncate">
{{ description }} {{ description }}
......
...@@ -5,7 +5,7 @@ import { formatNumber, __, s__ } from '~/locale'; ...@@ -5,7 +5,7 @@ import { formatNumber, __, s__ } from '~/locale';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import { RUNNER_JOB_COUNT_LIMIT } from '../constants'; import { RUNNER_JOB_COUNT_LIMIT } from '../constants';
import RunnerActionsCell from './cells/runner_actions_cell.vue'; import RunnerActionsCell from './cells/runner_actions_cell.vue';
import RunnerNameCell from './cells/runner_name_cell.vue'; import RunnerSummaryCell from './cells/runner_summary_cell.vue';
import RunnerTypeCell from './cells/runner_type_cell.vue'; import RunnerTypeCell from './cells/runner_type_cell.vue';
import RunnerTags from './runner_tags.vue'; import RunnerTags from './runner_tags.vue';
...@@ -35,7 +35,7 @@ export default { ...@@ -35,7 +35,7 @@ export default {
GlSkeletonLoader, GlSkeletonLoader,
TimeAgo, TimeAgo,
RunnerActionsCell, RunnerActionsCell,
RunnerNameCell, RunnerSummaryCell,
RunnerTags, RunnerTags,
RunnerTypeCell, RunnerTypeCell,
}, },
...@@ -77,7 +77,7 @@ export default { ...@@ -77,7 +77,7 @@ export default {
}, },
fields: [ fields: [
tableField({ key: 'type', label: __('Type/State') }), tableField({ key: 'type', label: __('Type/State') }),
tableField({ key: 'name', label: s__('Runners|Runner'), width: 30 }), tableField({ key: 'summary', label: s__('Runners|Runner'), width: 30 }),
tableField({ key: 'version', label: __('Version') }), tableField({ key: 'version', label: __('Version') }),
tableField({ key: 'ipAddress', label: __('IP Address') }), tableField({ key: 'ipAddress', label: __('IP Address') }),
tableField({ key: 'projectCount', label: __('Projects'), width: 5 }), tableField({ key: 'projectCount', label: __('Projects'), width: 5 }),
...@@ -107,8 +107,12 @@ export default { ...@@ -107,8 +107,12 @@ export default {
<runner-type-cell :runner="item" /> <runner-type-cell :runner="item" />
</template> </template>
<template #cell(name)="{ item }"> <template #cell(summary)="{ item, index }">
<runner-name-cell :runner="item" /> <runner-summary-cell :runner="item">
<template #runner-name="{ runner }">
<slot name="runner-name" :runner="runner" :index="index"></slot>
</template>
</runner-summary-cell>
</template> </template>
<template #cell(version)="{ item: { version } }"> <template #cell(version)="{ item: { version } }">
......
<script>
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
export default {
props: {
runner: {
type: Object,
required: true,
},
},
methods: {
getIdFromGraphQLId,
},
};
</script>
<template>
<span>#{{ getIdFromGraphQLId(runner.id) }} ({{ runner.shortSha }})</span>
</template>
...@@ -24,9 +24,12 @@ query getGroupRunners( ...@@ -24,9 +24,12 @@ query getGroupRunners(
search: $search search: $search
sort: $sort sort: $sort
) { ) {
nodes { edges {
webUrl
node {
...RunnerNode ...RunnerNode
} }
}
pageInfo { pageInfo {
...PageInfo ...PageInfo
} }
......
...@@ -25,6 +25,7 @@ query getRunners( ...@@ -25,6 +25,7 @@ query getRunners(
) { ) {
nodes { nodes {
...RunnerNode ...RunnerNode
adminUrl
} }
pageInfo { pageInfo {
...PageInfo ...PageInfo
......
<script> <script>
import { GlLink } from '@gitlab/ui';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { fetchPolicies } from '~/lib/graphql'; import { fetchPolicies } from '~/lib/graphql';
import { updateHistory } from '~/lib/utils/url_utility'; import { updateHistory } from '~/lib/utils/url_utility';
import { formatNumber, sprintf, s__ } from '~/locale'; import { formatNumber, sprintf, s__ } from '~/locale';
import RunnerFilteredSearchBar from '../components/runner_filtered_search_bar.vue'; import RunnerFilteredSearchBar from '../components/runner_filtered_search_bar.vue';
import RunnerList from '../components/runner_list.vue'; import RunnerList from '../components/runner_list.vue';
import RunnerManualSetupHelp from '../components/runner_manual_setup_help.vue'; import RunnerManualSetupHelp from '../components/runner_manual_setup_help.vue';
import RunnerName from '../components/runner_name.vue';
import RunnerPagination from '../components/runner_pagination.vue'; import RunnerPagination from '../components/runner_pagination.vue';
import RunnerTypeHelp from '../components/runner_type_help.vue'; import RunnerTypeHelp from '../components/runner_type_help.vue';
import { statusTokenConfig } from '../components/search_tokens/status_token_config'; import { statusTokenConfig } from '../components/search_tokens/status_token_config';
import { typeTokenConfig } from '../components/search_tokens/type_token_config'; import { typeTokenConfig } from '../components/search_tokens/type_token_config';
import { import {
...@@ -27,9 +31,11 @@ import { captureException } from '../sentry_utils'; ...@@ -27,9 +31,11 @@ import { captureException } from '../sentry_utils';
export default { export default {
name: 'GroupRunnersApp', name: 'GroupRunnersApp',
components: { components: {
GlLink,
RunnerFilteredSearchBar, RunnerFilteredSearchBar,
RunnerList, RunnerList,
RunnerManualSetupHelp, RunnerManualSetupHelp,
RunnerName,
RunnerTypeHelp, RunnerTypeHelp,
RunnerPagination, RunnerPagination,
}, },
...@@ -51,6 +57,7 @@ export default { ...@@ -51,6 +57,7 @@ export default {
return { return {
search: fromUrlQueryToSearch(), search: fromUrlQueryToSearch(),
runners: { runners: {
webUrls: [],
items: [], items: [],
pageInfo: {}, pageInfo: {},
}, },
...@@ -68,8 +75,10 @@ export default { ...@@ -68,8 +75,10 @@ export default {
}, },
update(data) { update(data) {
const { runners } = data?.group || {}; const { runners } = data?.group || {};
return { return {
items: runners?.nodes || [], webUrls: runners?.edges.map(({ webUrl }) => webUrl) || [],
items: runners?.edges.map(({ node }) => node) || [],
pageInfo: runners?.pageInfo || {}, pageInfo: runners?.pageInfo || {},
}; };
}, },
...@@ -163,7 +172,13 @@ export default { ...@@ -163,7 +172,13 @@ export default {
{{ __('No runners found') }} {{ __('No runners found') }}
</div> </div>
<template v-else> <template v-else>
<runner-list :runners="runners.items" :loading="runnersLoading" /> <runner-list :runners="runners.items" :loading="runnersLoading">
<template #runner-name="{ runner, index }">
<gl-link :href="runners.webUrls[index]">
<runner-name :runner="runner" />
</gl-link>
</template>
</runner-list>
<runner-pagination v-model="search.pagination" :page-info="runners.pageInfo" /> <runner-pagination v-model="search.pagination" :page-info="runners.pageInfo" />
</template> </template>
</div> </div>
......
import { GlLink } from '@gitlab/ui';
import { createLocalVue, mount, shallowMount } from '@vue/test-utils'; import { createLocalVue, mount, shallowMount } from '@vue/test-utils';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper'; import createMockApollo from 'helpers/mock_apollo_helper';
...@@ -5,6 +6,7 @@ import setWindowLocation from 'helpers/set_window_location_helper'; ...@@ -5,6 +6,7 @@ import setWindowLocation from 'helpers/set_window_location_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { updateHistory } from '~/lib/utils/url_utility'; import { updateHistory } from '~/lib/utils/url_utility';
import AdminRunnersApp from '~/runner/admin_runners/admin_runners_app.vue'; import AdminRunnersApp from '~/runner/admin_runners/admin_runners_app.vue';
...@@ -98,6 +100,20 @@ describe('AdminRunnersApp', () => { ...@@ -98,6 +100,20 @@ describe('AdminRunnersApp', () => {
expect(findRunnerList().props('runners')).toEqual(runnersData.data.runners.nodes); expect(findRunnerList().props('runners')).toEqual(runnersData.data.runners.nodes);
}); });
it('runner item links to the runner admin page', async () => {
createComponent({ mountFn: mount });
await waitForPromises();
const { id, shortSha } = runnersData.data.runners.nodes[0];
const numericId = getIdFromGraphQLId(id);
const runnerLink = wrapper.find('tr [data-testid="td-summary"]').find(GlLink);
expect(runnerLink.text()).toBe(`#${numericId} (${shortSha})`);
expect(runnerLink.attributes('href')).toBe(`http://localhost/admin/runners/${numericId}`);
});
it('requests the runners with no filters', () => { it('requests the runners with no filters', () => {
expect(mockRunnersQuery).toHaveBeenLastCalledWith({ expect(mockRunnersQuery).toHaveBeenLastCalledWith({
status: undefined, status: undefined,
......
...@@ -5,15 +5,18 @@ import { extendedWrapper } from 'helpers/vue_test_utils_helper'; ...@@ -5,15 +5,18 @@ import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash'; import createFlash from '~/flash';
import RunnerActionCell from '~/runner/components/cells/runner_actions_cell.vue'; import RunnerActionCell from '~/runner/components/cells/runner_actions_cell.vue';
import getGroupRunnersQuery from '~/runner/graphql/get_group_runners.query.graphql';
import getRunnersQuery from '~/runner/graphql/get_runners.query.graphql'; import getRunnersQuery from '~/runner/graphql/get_runners.query.graphql';
import runnerDeleteMutation from '~/runner/graphql/runner_delete.mutation.graphql'; import runnerDeleteMutation from '~/runner/graphql/runner_delete.mutation.graphql';
import runnerUpdateMutation from '~/runner/graphql/runner_update.mutation.graphql'; import runnerUpdateMutation from '~/runner/graphql/runner_update.mutation.graphql';
import { captureException } from '~/runner/sentry_utils'; import { captureException } from '~/runner/sentry_utils';
import { runnerData } from '../../mock_data'; import { runnersData, runnerData } from '../../mock_data';
const mockRunner = runnerData.data.runner; const mockRunner = runnersData.data.runners.nodes[0];
const mockRunnerDetails = runnerData.data.runner;
const getRunnersQueryName = getRunnersQuery.definitions[0].name.value; const getRunnersQueryName = getRunnersQuery.definitions[0].name.value;
const getGroupRunnersQueryName = getGroupRunnersQuery.definitions[0].name.value;
const localVue = createLocalVue(); const localVue = createLocalVue();
localVue.use(VueApollo); localVue.use(VueApollo);
...@@ -36,6 +39,7 @@ describe('RunnerTypeCell', () => { ...@@ -36,6 +39,7 @@ describe('RunnerTypeCell', () => {
propsData: { propsData: {
runner: { runner: {
id: mockRunner.id, id: mockRunner.id,
adminUrl: mockRunner.adminUrl,
active, active,
}, },
}, },
...@@ -61,7 +65,7 @@ describe('RunnerTypeCell', () => { ...@@ -61,7 +65,7 @@ describe('RunnerTypeCell', () => {
runnerUpdateMutationHandler.mockResolvedValue({ runnerUpdateMutationHandler.mockResolvedValue({
data: { data: {
runnerUpdate: { runnerUpdate: {
runner: runnerData.data.runner, runner: mockRunnerDetails,
errors: [], errors: [],
}, },
}, },
...@@ -78,7 +82,7 @@ describe('RunnerTypeCell', () => { ...@@ -78,7 +82,7 @@ describe('RunnerTypeCell', () => {
it('Displays the runner edit link with the correct href', () => { it('Displays the runner edit link with the correct href', () => {
createComponent(); createComponent();
expect(findEditBtn().attributes('href')).toBe('/admin/runners/1'); expect(findEditBtn().attributes('href')).toBe(mockRunner.adminUrl);
}); });
describe.each` describe.each`
...@@ -231,7 +235,7 @@ describe('RunnerTypeCell', () => { ...@@ -231,7 +235,7 @@ describe('RunnerTypeCell', () => {
}, },
}, },
awaitRefetchQueries: true, awaitRefetchQueries: true,
refetchQueries: [getRunnersQueryName], refetchQueries: [getRunnersQueryName, getGroupRunnersQueryName],
}); });
}); });
......
import { GlLink } from '@gitlab/ui';
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import RunnerNameCell from '~/runner/components/cells/runner_name_cell.vue'; import RunnerSummaryCell from '~/runner/components/cells/runner_summary_cell.vue';
const mockId = '1'; const mockId = '1';
const mockShortSha = '2P6oDVDm'; const mockShortSha = '2P6oDVDm';
...@@ -9,10 +8,8 @@ const mockDescription = 'runner-1'; ...@@ -9,10 +8,8 @@ const mockDescription = 'runner-1';
describe('RunnerTypeCell', () => { describe('RunnerTypeCell', () => {
let wrapper; let wrapper;
const findLink = () => wrapper.findComponent(GlLink); const createComponent = (options) => {
wrapper = mount(RunnerSummaryCell, {
const createComponent = () => {
wrapper = mount(RunnerNameCell, {
propsData: { propsData: {
runner: { runner: {
id: `gid://gitlab/Ci::Runner/${mockId}`, id: `gid://gitlab/Ci::Runner/${mockId}`,
...@@ -20,6 +17,7 @@ describe('RunnerTypeCell', () => { ...@@ -20,6 +17,7 @@ describe('RunnerTypeCell', () => {
description: mockDescription, description: mockDescription,
}, },
}, },
...options,
}); });
}; };
...@@ -31,12 +29,23 @@ describe('RunnerTypeCell', () => { ...@@ -31,12 +29,23 @@ describe('RunnerTypeCell', () => {
wrapper.destroy(); wrapper.destroy();
}); });
it('Displays the runner link with id and short token', () => { it('Displays the runner name as id and short token', () => {
expect(findLink().text()).toBe(`#${mockId} (${mockShortSha})`); expect(wrapper.text()).toContain(`#${mockId} (${mockShortSha})`);
expect(findLink().attributes('href')).toBe(`/admin/runners/${mockId}`);
}); });
it('Displays the runner description', () => { it('Displays the runner description', () => {
expect(wrapper.text()).toContain(mockDescription); expect(wrapper.text()).toContain(mockDescription);
}); });
it('Displays a custom slot', () => {
const slotContent = 'My custom runner summary';
createComponent({
slots: {
'runner-name': slotContent,
},
});
expect(wrapper.text()).toContain(slotContent);
});
}); });
import { GlLink, GlTable, GlSkeletonLoader } from '@gitlab/ui'; import { GlTable, GlSkeletonLoader } from '@gitlab/ui';
import { mount, shallowMount } from '@vue/test-utils'; import { mount, shallowMount } from '@vue/test-utils';
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash';
import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper';
...@@ -67,11 +67,11 @@ describe('RunnerList', () => { ...@@ -67,11 +67,11 @@ describe('RunnerList', () => {
// Badges // Badges
expect(findCell({ fieldKey: 'type' }).text()).toMatchInterpolatedText('specific paused'); expect(findCell({ fieldKey: 'type' }).text()).toMatchInterpolatedText('specific paused');
// Runner identifier // Runner summary
expect(findCell({ fieldKey: 'name' }).text()).toContain( expect(findCell({ fieldKey: 'summary' }).text()).toContain(
`#${getIdFromGraphQLId(id)} (${shortSha})`, `#${getIdFromGraphQLId(id)} (${shortSha})`,
); );
expect(findCell({ fieldKey: 'name' }).text()).toContain(description); expect(findCell({ fieldKey: 'summary' }).text()).toContain(description);
// Other fields // Other fields
expect(findCell({ fieldKey: 'version' }).text()).toBe(version); expect(findCell({ fieldKey: 'version' }).text()).toBe(version);
...@@ -136,12 +136,11 @@ describe('RunnerList', () => { ...@@ -136,12 +136,11 @@ describe('RunnerList', () => {
}); });
}); });
it('Links to the runner page', () => { it('Shows runner identifier', () => {
const { id } = mockRunners[0]; const { id, shortSha } = mockRunners[0];
const numericId = getIdFromGraphQLId(id);
expect(findCell({ fieldKey: 'name' }).find(GlLink).attributes('href')).toBe( expect(findCell({ fieldKey: 'summary' }).text()).toContain(`#${numericId} (${shortSha})`);
`/admin/runners/${getIdFromGraphQLId(id)}`,
);
}); });
describe('When data is loading', () => { describe('When data is loading', () => {
......
import { GlLink } from '@gitlab/ui';
import { createLocalVue, shallowMount, mount } from '@vue/test-utils'; import { createLocalVue, shallowMount, mount } from '@vue/test-utils';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper'; import createMockApollo from 'helpers/mock_apollo_helper';
...@@ -5,6 +6,7 @@ import setWindowLocation from 'helpers/set_window_location_helper'; ...@@ -5,6 +6,7 @@ import setWindowLocation from 'helpers/set_window_location_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { updateHistory } from '~/lib/utils/url_utility'; import { updateHistory } from '~/lib/utils/url_utility';
import RunnerFilteredSearchBar from '~/runner/components/runner_filtered_search_bar.vue'; import RunnerFilteredSearchBar from '~/runner/components/runner_filtered_search_bar.vue';
...@@ -34,8 +36,7 @@ localVue.use(VueApollo); ...@@ -34,8 +36,7 @@ localVue.use(VueApollo);
const mockGroupFullPath = 'group1'; const mockGroupFullPath = 'group1';
const mockRegistrationToken = 'AABBCC'; const mockRegistrationToken = 'AABBCC';
const mockRunners = groupRunnersData.data.group.runners.nodes; const mockGroupRunnersLimitedCount = groupRunnersData.data.group.runners.edges.length;
const mockGroupRunnersLimitedCount = mockRunners.length;
jest.mock('~/flash'); jest.mock('~/flash');
jest.mock('~/runner/sentry_utils'); jest.mock('~/runner/sentry_utils');
...@@ -91,7 +92,22 @@ describe('GroupRunnersApp', () => { ...@@ -91,7 +92,22 @@ describe('GroupRunnersApp', () => {
}); });
it('shows the runners list', () => { it('shows the runners list', () => {
expect(findRunnerList().props('runners')).toEqual(groupRunnersData.data.group.runners.nodes); expect(findRunnerList().props('runners')).toEqual(
groupRunnersData.data.group.runners.edges.map(({ node }) => node),
);
});
it('runner item links to the runner group page', async () => {
const { webUrl, node } = groupRunnersData.data.group.runners.edges[0];
const { id, shortSha } = node;
createComponent({ mountFn: mount });
await waitForPromises();
const runnerLink = wrapper.find('tr [data-testid="td-summary"]').find(GlLink);
expect(runnerLink.text()).toBe(`#${getIdFromGraphQLId(id)} (${shortSha})`);
expect(runnerLink.attributes('href')).toBe(webUrl);
}); });
it('requests the runners with group path and no other filters', () => { it('requests the runners with group path and no other filters', () => {
......
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