Skip to content

Commit

Permalink
fix(#2324): Shutdown button calls restart endpoint (#2337)
Browse files Browse the repository at this point in the history
closes #2324
  • Loading branch information
SteKoe committed Mar 15, 2023
1 parent eeb0465 commit 41e9cfc
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 70 deletions.
4 changes: 4 additions & 0 deletions spring-boot-admin-server-ui/.jest/jest.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import '@testing-library/jest-dom';

import { server } from '@/mocks/server';

afterEach(() => {
document.body.innerHTML = '';
});

beforeAll(async () => {
server.listen();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<template>
<TransitionRoot
ref="root"
appear
:show="isOpen"
appear
as="template"
@close="closeModal"
>
Expand Down Expand Up @@ -63,10 +63,9 @@ import {
TransitionChild,
TransitionRoot,
} from '@headlessui/vue';
import { defineComponent, ref, render } from 'vue';
import { defineComponent, ref } from 'vue';
import eventBus from '@/plugins/modal/bus';
import { removeElement } from '@/plugins/modal/helpers';
export default defineComponent({
components: {
Expand Down Expand Up @@ -97,12 +96,6 @@ export default defineComponent({
methods: {
closeModal() {
this.isOpen = false;
setTimeout(() => {
const wrapper = this.$refs.root;
render(null, wrapper);
removeElement(wrapper);
}, 150);
},
},
});
Expand Down
20 changes: 16 additions & 4 deletions spring-boot-admin-server-ui/src/main/frontend/plugins/modal/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,35 @@ export const useModal = (globalProps = {}) => {
};

const propsData = Object.assign({}, defaultProps, globalProps, options);
createComponent(Modal, propsData, document.body, slots);
return createComponent(Modal, propsData, document.body, slots);
},
async confirm(title, body) {
this.open(
let bodyFn = () =>
h(
'span',
{
innerHTML: body,
},
[]
);

const { vNode, destroy } = this.open(
{ title },
{
buttons: () =>
h(ConfirmButtons, {
labelOk: t('term.ok'),
labelCancel: t('term.cancel'),
}),
body: () => h('span', { innerHTML: body }),
body: bodyFn,
}
);

return new Promise((resolve) => {
eventBus.on('sba-modal-close', resolve);
eventBus.on('sba-modal-close', (result) => {
destroy();
resolve(result);
});
});
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,22 @@ export function removeElement(el) {
}

export function createComponent(component, props, parentContainer, slots = {}) {
const vNode = h(component, props, slots);
let vNode = h(component, props, slots);

let container = parentContainer.querySelector('.sba-modal--wrapper');
container = container || document.createElement('div');
container.classList.add('sba-modal--wrapper');
parentContainer.appendChild(container);
render(vNode, container);

return vNode.component;
const destroy = () => {
if (container) render(null, container);
container = null;
vNode = null;
};

return {
vNode,
destroy,
};
}
3 changes: 2 additions & 1 deletion spring-boot-admin-server-ui/src/main/frontend/test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,6 @@ export const render = (testComponent, options) => {
},
options
);
return tlRender(testComponent, renderOptions);
let utils = tlRender(testComponent, renderOptions);
return { ...utils };
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,76 +14,123 @@
* limitations under the License.
*/
import userEvent from '@testing-library/user-event';
import { screen, waitFor } from '@testing-library/vue';
import { screen, waitFor, within } from '@testing-library/vue';
import { cloneDeep } from 'lodash-es';

import { applications } from '../../mocks/applications/data';
import Application from '../../services/application';
import { render } from '../../test-utils';
import ApplicationListItem from './applications-list-item';

describe('application-list-item.vue', () => {
let application;
import { applications } from '@/mocks/applications/data';
import { render } from '@/test-utils';

beforeEach(() => {
application = cloneDeep(applications[0]);
async function clickConfirmModal() {
await waitFor(() => {
expect(screen.getByRole('dialog')).toBeInTheDocument();
});

it('does not show shutdown button when shutdown endpoint is missing', () => {
application.instances[0].endpoints = [];
const buttonOK = screen.queryByRole('button', { name: 'term.ok' });
await userEvent.click(buttonOK);
}

render(ApplicationListItem, {
props: { application: new Application(application) },
describe('application-list-item.vue', () => {
describe('unregister', () => {
it('on instance', async () => {
let application = new Application(cloneDeep(applications[0]));
const { emitted } = render(ApplicationListItem, {
props: { application, isExpanded: true },
});

const htmlElement = await screen.findByTestId(
application.instances[0].id
);
const element = within(htmlElement).queryByTitle(
'applications.actions.unregister'
);
await userEvent.click(element);

await clickConfirmModal();

await waitFor(() => expect(emitted('unregister')).toBeDefined());
});

const shutdownButton = screen.queryByTitle('shutdown');
expect(shutdownButton).toBeNull();
});
it('on application', async () => {
const { emitted } = render(ApplicationListItem, {
props: { application: new Application(cloneDeep(applications[0])) },
});

it('should call shutdown endpoint when modal is confirmed', async () => {
const { emitted } = render(ApplicationListItem, {
props: { application: new Application(application) },
});
const element = screen.queryByTitle('applications.actions.unregister');
await userEvent.click(element);

const element = screen.queryByTitle('shutdown');
await userEvent.click(element);
await clickConfirmModal();

await waitFor(() => {
screen.findByRole('dialog');
await waitFor(() => expect(emitted('unregister')).toBeDefined());
});
});

const buttonOK = screen.queryByRole('button', { name: 'OK' });
await userEvent.click(buttonOK);
describe('restart', () => {
it('on instance', async () => {
let application = new Application(cloneDeep(applications[0]));
const { emitted } = render(ApplicationListItem, {
props: { application, isExpanded: true },
});

expect(emitted()).toBeDefined();
});
const htmlElement = await screen.findByTestId(
application.instances[0].id
);
const element = within(htmlElement).queryByTitle(
'applications.actions.restart'
);
await userEvent.click(element);

it('does not show restart button when restart endpoint is missing', () => {
application.instances[0].endpoints = [];
await clickConfirmModal();

render(ApplicationListItem, {
props: { application: new Application(application) },
await waitFor(() => expect(emitted('restart')).toBeDefined());
});

const shutdownButton = screen.queryByTitle('applications.actions.restart');
expect(shutdownButton).toBeNull();
});
it('on application', async () => {
const { emitted } = render(ApplicationListItem, {
props: { application: new Application(cloneDeep(applications[0])) },
});

const element = screen.queryByTitle('applications.actions.restart');
await userEvent.click(element);

await clickConfirmModal();

it('should call restart endpoint when modal is confirmed', async () => {
const { emitted } = render(ApplicationListItem, {
props: { application: new Application(application) },
await waitFor(() => expect(emitted('restart')).toBeDefined());
});
});

describe('shutdown', () => {
it('on application', async () => {
const { emitted } = render(ApplicationListItem, {
props: { application: new Application(cloneDeep(applications[0])) },
});

const element = await screen.findByTitle('applications.actions.shutdown');
await userEvent.click(element);

await clickConfirmModal();

const element = screen.queryByTitle('applications.actions.restart');
await userEvent.click(element);
await waitFor(() => {
screen.findByRole('dialog');
expect(emitted('shutdown')).toBeDefined();
});

const buttonOK = screen.queryByRole('button', { name: 'term.ok' });
await userEvent.click(buttonOK);
it('on instance', async () => {
let application = new Application(cloneDeep(applications[0]));
const { emitted } = render(ApplicationListItem, {
props: { application, isExpanded: true },
});

let emitted1 = emitted();
expect(emitted1.restart).toBeDefined();
let htmlElement = await screen.findByTestId(application.instances[0].id);

const element = await within(htmlElement).findByTitle(
'applications.actions.shutdown'
);
await userEvent.click(element);

await clickConfirmModal();

expect(emitted('shutdown')).toBeDefined();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@
<div
:id="application.name"
v-on-clickaway="(event) => $emit('deselect', event, application.name)"
class="application-list-item"
:class="{ 'is-active': isExpanded }"
class="application-list-item"
@click="$emit('select', application.name)"
>
<header
class="application-list-item__header"
:class="headerClass"
class="application-list-item__header"
v-on="$attrs"
>
<ApplicationsListItemSummary
Expand All @@ -38,15 +38,15 @@
/>
<div>
<ApplicationListItemAction
:item="application"
:has-active-notification-filter="
hasActiveNotificationFilter(application)
"
:has-notification-filters-support="hasNotificationFiltersSupport"
@filter-settings="toggleFilterSettings"
:item="application"
@restart="confirmRestartApplication"
@shutdown="confirmShutdownApplication"
@unregister="confirmUnregisterApplication"
@filter-settings="toggleFilterSettings"
/>
</div>
</header>
Expand All @@ -55,16 +55,16 @@
<instances-list :instances="application.instances">
<template #actions="{ instance }">
<ApplicationListItemAction
class="hidden md:flex"
:item="instance"
:has-active-notification-filter="
hasActiveNotificationFilter(instance)
"
:has-notification-filters-support="hasNotificationFiltersSupport"
@filter-settings="toggleFilterSettings"
:item="instance"
class="hidden md:flex"
@restart="confirmRestartInstance"
@shutdown="confirmShutdownInstance"
@unregister="confirmUnregisterInstance"
@filter-settings="toggleFilterSettings"
/>
</template>
</instances-list>
Expand Down Expand Up @@ -135,7 +135,7 @@ export default {
this.$t('applications.shutdown', { name: application.name })
);
if (isConfirmed) {
this.$emit('restart', application);
this.$emit('shutdown', application);
}
},
async confirmUnregisterApplication(application) {
Expand Down Expand Up @@ -180,7 +180,7 @@ export default {
this.$t('instances.shutdown', { name: instance.id })
);
if (isConfirmed) {
this.$emit('restart', instance);
this.$emit('shutdown', instance);
}
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
},
"instances": {
"shutdown": "Shutdown instance <code>{name}</code>?",
"shutdown_successful": "Successfully restarted instances {name}.",
"shutdown_successful": "Successfully shutdown instances {name}.",
"shutdown_failed": "Failed to shutdown instances {name}.",
"restart": "Restart instance <code>{name}</code>?",
"restarted": "Successfully restarted instance {name}.",
"unregister": "Deregister instance <code>{name}</code>?",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<li
v-for="instance in instances"
:key="instance.id"
:data-testid="instance.id"
class="flex items-center hover:bg-gray-100 p-2"
@click.stop="showDetails(instance)"
>
Expand Down

0 comments on commit 41e9cfc

Please sign in to comment.