Skip to content

Commit

Permalink
feat: add a way to debug stores in troubleshooting page
Browse files Browse the repository at this point in the history
fixes containers#3053

Signed-off-by: Florent Benoit <fbenoit@redhat.com>
  • Loading branch information
benoitf committed Jul 5, 2023
1 parent 0255774 commit 7176fb0
Show file tree
Hide file tree
Showing 8 changed files with 463 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function copyLogsToClipboard() {
}
</script>

<div class="flex flex-col bg-zinc-700 m-4 p-4 mb-10">
<div class="flex flex-col bg-zinc-700 m-4 p-4">
<div class="flex flex-row align-middle items-center w-full">
<Fa size="40" icon="{faFileLines}" />
<div class="mx-2 text-xl">Logs</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@
import NavPage from '../ui/NavPage.svelte';
import TroubleshootingDevToolsConsoleLogs from './TroubleshootingDevToolsConsoleLogs.svelte';
import TroubleshootingPageProviders from './TroubleshootingPageProviders.svelte';
import TroubleshootingPageStores from './TroubleshootingPageStores.svelte';
</script>

<NavPage title="Troubleshooting" searchEnabled="{false}">
<div slot="content" class="flex flex-col">
<TroubleshootingPageProviders />

<TroubleshootingDevToolsConsoleLogs />

<TroubleshootingPageStores />
</div>
</NavPage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**********************************************************************
* Copyright (C) 2023 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
***********************************************************************/

/* eslint-disable @typescript-eslint/no-explicit-any */

import '@testing-library/jest-dom';
import { beforeAll, test, expect, vi } from 'vitest';
import { fireEvent, render, screen } from '@testing-library/svelte';
import TroubleshootingPageStore from './TroubleshootingPageStore.svelte';
import type { EventStoreInfo } from '/@/stores/event-store';

beforeAll(() => {});

test('Check store info is displayed and clicking on buttons works', async () => {
const clearEventsMock = vi.fn();
const fetchMock = vi.fn();

const eventStoreInfo: EventStoreInfo = {
name: 'my-test-store',
size: 3,
bufferEvents: [],
clearEvents: clearEventsMock,
fetch: fetchMock,
};

render(TroubleshootingPageStore, { eventStoreInfo });

// expect to have the Refresh button
const refreshButton = screen.getByRole('button', { name: 'Refresh' });
expect(refreshButton).toBeInTheDocument();

// click on it
await fireEvent.click(refreshButton);

// expect to have fetch method called
expect(fetchMock).toHaveBeenCalled();

// check we have open details button
const openDetailsButton = screen.getByRole('button', { name: 'Open Details' });
expect(openDetailsButton).toBeInTheDocument();

// click on it
await fireEvent.click(openDetailsButton);

// expect to have dialog being displayed when clicking on the button
const details = screen.getByRole('dialog', { name: 'Details of my-test-store' });

expect(details).toBeInTheDocument();

// expect to have the Cancel button
const cancelButton = screen.getByRole('button', { name: 'Cancel' });
expect(cancelButton).toBeInTheDocument();

// click on it
await fireEvent.click(cancelButton);

// dialog should be hidden now
expect(details).not.toBeInTheDocument();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<script lang="ts">
import TroubleshootingPageStoreDetails from './TroubleshootingPageStoreDetails.svelte';
import type { EventStoreInfo } from '/@/stores/event-store';
export let eventStoreInfo: EventStoreInfo;
let fetchInProgress = false;
async function fetch(): Promise<void> {
fetchInProgress = true;
try {
await eventStoreInfo.fetch();
} finally {
fetchInProgress = false;
}
}
let openDetails = false;
</script>

<div class="flex flex-col bg-charcoal-600 p-2 items-center rounded w-full">
<div><svelte:component this="{eventStoreInfo.iconComponent}" size="20" /></div>
<div class="text-xl">
<button
disabled="{fetchInProgress}"
class="underline outline-none"
title="Open Details"
aria-label="Open Details"
on:click="{() => (openDetails = true)}">
{eventStoreInfo.name}
</button>
</div>
<div class="text-sm">({eventStoreInfo.size} items)</div>
<div class="">
<button
disabled="{fetchInProgress}"
class="px-3 my-1 text-sm font-medium text-center text-white bg-violet-600 rounded-sm hover:bg-dustypurple-800 focus:ring-2 focus:outline-none focus:ring-dustypurple-700 w-full"
title="Refresh"
aria-label="Refresh"
on:click="{() => fetch()}">
Refresh
</button>
</div>
{#if eventStoreInfo.bufferEvents.length > 0}
{@const lastUpdate = eventStoreInfo.bufferEvents[eventStoreInfo.bufferEvents.length - 1]}
{#if lastUpdate.humanDuration}
<div class="text-xs italic" title="Time to update">{lastUpdate.humanDuration}</div>
{/if}
{/if}

{#if openDetails}
<TroubleshootingPageStoreDetails
closeCallback="{() => {
openDetails = false;
}}"
eventStoreInfo="{eventStoreInfo}" />
{/if}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/**********************************************************************
* Copyright (C) 2023 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
***********************************************************************/

/* eslint-disable @typescript-eslint/no-explicit-any */

import '@testing-library/jest-dom';
import { beforeAll, test, expect, vi } from 'vitest';
import { fireEvent, render, screen } from '@testing-library/svelte';
import TroubleshootingPageStoreDetails from './TroubleshootingPageStoreDetails.svelte';
import type { EventStoreInfo } from '/@/stores/event-store';
import userEvent from '@testing-library/user-event';

beforeAll(() => {});

test('Check details are displayed and works', async () => {
const clearEventsMock = vi.fn();
const fetchMock = vi.fn();
const closeCallback = vi.fn();

const bufferEvent = {
name: 'my-test-event',
args: [],
length: 5,
date: new Date().getTime(),
skipped: false,
};

const eventStoreInfo: EventStoreInfo = {
name: 'my-test-store',
size: 3,
bufferEvents: [bufferEvent],
clearEvents: clearEventsMock,
fetch: fetchMock,
};

render(TroubleshootingPageStoreDetails, { eventStoreInfo, closeCallback });

// find the label with name size
const sizeStatus = screen.getByRole('status', { name: 'size' });
expect(sizeStatus).toBeInTheDocument();
// value should be 3
expect(sizeStatus).toHaveTextContent('3');

// and check we have buffer events
const bufferEvents = screen.getByRole('list', { name: 'buffer-events' });
expect(bufferEvents).toBeInTheDocument();

// expect to have li item in the list
const bufferEvent1 = screen.getByRole('listitem', { name: 'my-test-event' });
expect(bufferEvent1).toBeInTheDocument();
// now check the text content
expect(bufferEvent1).toHaveTextContent(`Grab ${bufferEvent.length} items from '${bufferEvent.name}' event`);
});

test('Check close button', async () => {
const clearEventsMock = vi.fn();
const fetchMock = vi.fn();
const closeCallback = vi.fn();

const eventStoreInfo: EventStoreInfo = {
name: 'my-test-store',
size: 3,
bufferEvents: [],
clearEvents: clearEventsMock,
fetch: fetchMock,
};

render(TroubleshootingPageStoreDetails, { eventStoreInfo, closeCallback });

// expect to have the close button
const closeButton = screen.getByRole('button', { name: 'Close' });
expect(closeButton).toBeInTheDocument();

// click on close button and expect close callback to be called
expect(closeCallback).not.toBeCalled();
await fireEvent.click(closeButton);
expect(closeCallback).toBeCalled();
});

test('Check Cancel button', async () => {
const clearEventsMock = vi.fn();
const fetchMock = vi.fn();
const closeCallback = vi.fn();

const eventStoreInfo: EventStoreInfo = {
name: 'my-test-store',
size: 3,
bufferEvents: [],
clearEvents: clearEventsMock,
fetch: fetchMock,
};

render(TroubleshootingPageStoreDetails, { eventStoreInfo, closeCallback });

// expect to have the close button
const cancelButton = screen.getByRole('button', { name: 'Cancel' });
expect(cancelButton).toBeInTheDocument();

// click on Cancel button and expect close callback to be called
expect(closeCallback).not.toBeCalled();
await fireEvent.click(cancelButton);
expect(closeCallback).toBeCalled();
});

test('Check ESC key', async () => {
const clearEventsMock = vi.fn();
const fetchMock = vi.fn();
const closeCallback = vi.fn();

const eventStoreInfo: EventStoreInfo = {
name: 'my-test-store',
size: 3,
bufferEvents: [],
clearEvents: clearEventsMock,
fetch: fetchMock,
};

render(TroubleshootingPageStoreDetails, { eventStoreInfo, closeCallback });

// click on Cancel button and expect close callback to be called
expect(closeCallback).not.toBeCalled();
// now, press the ESC key
await userEvent.keyboard('{Escape}');
expect(closeCallback).toBeCalled();
});

0 comments on commit 7176fb0

Please sign in to comment.