From 47fc412474d08b1b9d18eb7df4c5b1af5c1a18d3 Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Wed, 3 Jan 2024 13:27:54 -0800 Subject: [PATCH 01/14] fix support for observability visualizations Signed-off-by: Shenoy Pratik --- .../paragraph_components/para_output.tsx | 151 +++++++++--------- 1 file changed, 79 insertions(+), 72 deletions(-) diff --git a/public/components/notebooks/components/paragraph_components/para_output.tsx b/public/components/notebooks/components/paragraph_components/para_output.tsx index dfd8a585d..44af810b4 100644 --- a/public/components/notebooks/components/paragraph_components/para_output.tsx +++ b/public/components/notebooks/components/paragraph_components/para_output.tsx @@ -6,9 +6,8 @@ import { EuiCodeBlock, EuiSpacer, EuiText } from '@elastic/eui'; import MarkdownRender from '@nteract/markdown'; import { Media } from '@nteract/outputs'; +import moment from 'moment'; import React, { useState } from 'react'; -import { VisualizationContainer } from '../../../../components/custom_panels/panel_modules/visualization_container'; -import PPLService from '../../../../services/requests/ppl'; import { CoreStart } from '../../../../../../../src/core/public'; import { DashboardContainerInput, @@ -16,8 +15,9 @@ import { } from '../../../../../../../src/plugins/dashboard/public'; import { ParaType } from '../../../../../common/types/notebooks'; import { getOSDHttp, getPPLService, uiSettingsService } from '../../../../../common/utils'; +import { VisualizationContainer } from '../../../../components/custom_panels/panel_modules/visualization_container'; +import PPLService from '../../../../services/requests/ppl'; import { QueryDataGridMemo } from './para_query_grid'; -import { convertDateTime } from '../../../common/query_utils'; const createQueryColumns = (jsonColumns: any[]) => { let index = 0; @@ -53,44 +53,19 @@ const getQueryOutputData = (queryObject: any) => { return data; }; -const QueryPara = ({ inp, val }) => { - const inputQuery = inp.substring(4, inp.length); - const queryObject = JSON.parse(val); - - const columns = createQueryColumns(queryObject.schema); - const [visibleColumns, setVisibleColumns] = useState(columns.map((c) => c.id)); - const data = getQueryOutputData(queryObject); - - return queryObject.hasOwnProperty('error') ? ( - {val} - ) : ( -
- - {inputQuery} - - - -
- ); -}; - const OutputBody = ({ + key, typeOut, val, - inp, + para, visInput, setVisInput, DashboardContainerByValueRenderer, }: { + key: string; typeOut: string; val: string; - inp: string; + para: ParaType; visInput: DashboardContainerInput; setVisInput: (input: DashboardContainerInput) => void; DashboardContainerByValueRenderer: DashboardStart['DashboardContainerByValueRenderer']; @@ -99,74 +74,104 @@ const OutputBody = ({ * Currently supports HTML, TABLE, IMG * TODO: add table rendering */ + const dateFormat = uiSettingsService.get('dateFormat'); - const from = convertDateTime(visInput?.timeRange?.from, true, false); - const to = convertDateTime(visInput?.timeRange?.to, false, false); - const displayFrom = - convertDateTime(visInput?.timeRange?.from, true, dateFormat) || 'Invalid date'; - const displayTo = convertDateTime(visInput?.timeRange?.to, false, dateFormat) || 'Invalid date'; + const [visibleColumns, setVisibleColumns] = useState([]); + if (typeOut !== undefined) { switch (typeOut) { case 'QUERY': - return ; + const inputQuery = para.inp.substring(4, para.inp.length); + const queryObject = JSON.parse(val); + if (queryObject.hasOwnProperty('error')) { + return {val}; + } else { + const columns = createQueryColumns(queryObject.schema); + const data = getQueryOutputData(queryObject); + setVisibleColumns(columns.map(({ id }) => id)); + return ( +
+ + {inputQuery} + + + +
+ ); + } case 'MARKDOWN': return ( - + ); case 'VISUALIZATION': + let from = moment(visInput?.timeRange?.from).format(dateFormat); + let to = moment(visInput?.timeRange?.to).format(dateFormat); + from = from === 'Invalid date' ? visInput.timeRange.from : from; + to = to === 'Invalid date' ? visInput.timeRange.to : to; return ( <> - {`${displayFrom} - ${displayTo}`} + {`${from} - ${to}`} - + ); case 'OBSERVABILITY_VISUALIZATION': - const http = getOSDHttp(); - const pplService = getPPLService(); - + let fromObs = moment(visInput?.timeRange?.from).format(dateFormat); + let toObs = moment(visInput?.timeRange?.to).format(dateFormat); + fromObs = fromObs === 'Invalid date' ? visInput.timeRange.from : fromObs; + toObs = toObs === 'Invalid date' ? visInput.timeRange.to : toObs; const onEditClick = (savedVisualizationId: string) => { window.location.assign(`observability-logs#/explorer/${savedVisualizationId}`); }; return ( <> - {`${displayFrom} - ${displayTo}`} + {`${fromObs} - ${toObs}`}
); case 'HTML': return ( - + {/* eslint-disable-next-line react/jsx-pascal-case */} ); case 'TABLE': - return
{val}
; + return
{val}
; case 'IMG': - return ; + return ; default: - return
{val}
; + return
{val}
; } } else { console.log('output not supported', typeOut); @@ -193,21 +198,23 @@ export const ParaOutput = (props: { }) => { const { para, DashboardContainerByValueRenderer, visInput, setVisInput } = props; - return !para.isOutputHidden ? ( - <> - {para.typeOut.map((typeOut: string, tIdx: number) => { - return ( - - ); - })} - - ) : null; + return ( + !para.isOutputHidden && ( + <> + {para.typeOut.map((typeOut: string, tIdx: number) => { + return ( + + ); + })} + + ) + ); }; From 5420b1522b052d9f74dcc9b45b6a9900c75d2180 Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Thu, 14 Dec 2023 10:26:56 -0800 Subject: [PATCH 02/14] update note_table tests Signed-off-by: Shenoy Pratik --- .../components/__tests__/note_table.test.tsx | 317 +++++++++++++----- .../notebooks/components/note_table.tsx | 7 +- 2 files changed, 240 insertions(+), 84 deletions(-) diff --git a/public/components/notebooks/components/__tests__/note_table.test.tsx b/public/components/notebooks/components/__tests__/note_table.test.tsx index 03ecd93a8..747404fdf 100644 --- a/public/components/notebooks/components/__tests__/note_table.test.tsx +++ b/public/components/notebooks/components/__tests__/note_table.test.tsx @@ -3,8 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { fireEvent, render, waitFor } from '@testing-library/react'; -import { configure, mount, shallow } from 'enzyme'; +import '@testing-library/jest-dom'; +import { act, cleanup, fireEvent, render, waitFor } from '@testing-library/react'; +import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; import { NoteTable } from '../note_table'; @@ -23,109 +24,261 @@ jest.mock('react-router-dom', () => ({ describe(' spec', () => { configure({ adapter: new Adapter() }); + const props = { + loading: false, + fetchNotebooks: jest.fn(), + addSampleNotebooks: jest.fn(), + createNotebook: jest.fn(), + renameNotebook: jest.fn(), + cloneNotebook: jest.fn(), + deleteNotebook: jest.fn(), + parentBreadcrumb: { href: 'parent-href', text: 'parent-text' }, + setBreadcrumbs: jest.fn(), + setToast: jest.fn(), + }; + + const renderNoteTable = (overrides = {}) => { + const utils = render(); + // Additional setup or assertions if needed + return utils; + }; + + afterEach(() => { + cleanup(); // Cleanup the rendered component after each test + }); + it('renders the empty component', () => { - const fetchNotebooks = jest.fn(); - const addSampleNotebooks = jest.fn(); - const createNotebook = jest.fn(); - const renameNotebook = jest.fn(); - const cloneNotebook = jest.fn(); - const deleteNotebook = jest.fn(); - const setBreadcrumbs = jest.fn(); - const setToast = jest.fn(); - const utils = render( - - ); + const utils = renderNoteTable({ notebooks: [] }); expect(utils.container.firstChild).toMatchSnapshot(); }); it('renders the component', () => { - const fetchNotebooks = jest.fn(); - const addSampleNotebooks = jest.fn(); - const createNotebook = jest.fn(); - const renameNotebook = jest.fn(); - const cloneNotebook = jest.fn(); - const deleteNotebook = jest.fn(); - const setBreadcrumbs = jest.fn(); - const setToast = jest.fn(); const notebooks = Array.from({ length: 5 }, (v, k) => ({ path: `path-${k}`, id: `id-${k}`, dateCreated: '2023-01-01 12:00:00', dateModified: '2023-01-02 12:00:00', })); - const utils = render( - - ); + const utils = renderNoteTable({ notebooks }); expect(utils.container.firstChild).toMatchSnapshot(); - utils.getByText('Actions').click(); - utils.getByText('Add samples').click(); - utils.getAllByLabelText('Select this row')[0].click(); - utils.getByText('Actions').click(); - utils.getByText('Delete').click(); - utils.getByText('Cancel').click(); - utils.getAllByLabelText('Select this row')[0].click(); - utils.getByText('Actions').click(); - utils.getByText('Rename').click(); + fireEvent.click(utils.getByText('Actions')); + fireEvent.click(utils.getByText('Add samples')); + fireEvent.click(utils.getAllByLabelText('Select this row')[0]); + fireEvent.click(utils.getByText('Actions')); + fireEvent.click(utils.getByText('Delete')); + fireEvent.click(utils.getByText('Cancel')); + fireEvent.click(utils.getAllByLabelText('Select this row')[0]); + fireEvent.click(utils.getByText('Actions')); + fireEvent.click(utils.getByText('Rename')); }); - it('create notebook', async () => { - const fetchNotebooks = jest.fn(); - const addSampleNotebooks = jest.fn(); - const createNotebook = jest.fn(); - const renameNotebook = jest.fn(); - const cloneNotebook = jest.fn(); - const deleteNotebook = jest.fn(); - const setBreadcrumbs = jest.fn(); - const setToast = jest.fn(); + it('create notebook modal', async () => { const notebooks = Array.from({ length: 5 }, (v, k) => ({ path: `path-${k}`, id: `id-${k}`, dateCreated: 'date-created', dateModified: 'date-modified', })); - const utils = render( - - ); - utils.getByText('Create notebook').click(); + const utils = renderNoteTable({ notebooks }); + fireEvent.click(utils.getByText('Create notebook')); await waitFor(() => { expect(global.window.location.href).toContain('/create'); }); }); + + it('filters notebooks based on search input', () => { + const { getByPlaceholderText, getAllByText, queryByText } = renderNoteTable({ + notebooks: [ + { + path: 'path-1', + id: 'id-1', + dateCreated: 'date-created', + dateModified: 'date-modified', + }, + ], + }); + + const searchInput = getByPlaceholderText('Search notebook name'); + fireEvent.change(searchInput, { target: { value: 'path-1' } }); + + // Assert that only the matching notebook is displayed + expect(getAllByText('path-1')).toHaveLength(1); + expect(queryByText('path-0')).toBeNull(); + expect(queryByText('path-2')).toBeNull(); + }); + + it('displays empty state message and create notebook button', () => { + const { getAllByText, getAllByTestId } = renderNoteTable({ notebooks: [] }); + + expect(getAllByText('No notebooks')).toHaveLength(1); + + // Create notebook using the modal + fireEvent.click(getAllByText('Create notebook')[0]); + fireEvent.click(getAllByTestId('custom-input-modal-input')[0]); + fireEvent.input(getAllByTestId('custom-input-modal-input')[0], { + target: { value: 'test-notebook' }, + }); + fireEvent.click(getAllByText('Create')[0]); + expect(props.createNotebook).toHaveBeenCalledTimes(1); + }); + + it('renames a notebook', () => { + const notebooks = [ + { + path: 'path-1', + id: 'id-1', + dateCreated: 'date-created', + dateModified: 'date-modified', + }, + ]; + const { getByText, getByLabelText, getAllByText, getByTestId } = renderNoteTable({ notebooks }); + + // Select a notebook + fireEvent.click(getByLabelText('Select this row')); + + // Open Actions dropdown and click Rename + fireEvent.click(getByText('Actions')); + fireEvent.click(getByText('Rename')); + + // Ensure the modal is open (you may need to adjust based on your modal implementation) + expect(getAllByText('Rename notebook')).toHaveLength(1); + + // Mock user input and submit + fireEvent.input(getByTestId('custom-input-modal-input'), { + target: { value: 'test-notebook-newname' }, + }); + fireEvent.click(getByTestId('custom-input-modal-confirm-button')); + + // Assert that the renameNotebook function is called + expect(props.renameNotebook).toHaveBeenCalledTimes(1); + expect(props.renameNotebook).toHaveBeenCalledWith('test-notebook-newname', 'id-1'); + }); + + it('clones a notebook', () => { + const notebooks = [ + { + path: 'path-1', + id: 'id-1', + dateCreated: 'date-created', + dateModified: 'date-modified', + }, + ]; + const { getByText, getByLabelText, getAllByText, getByTestId } = renderNoteTable({ notebooks }); + + // Select a notebook + fireEvent.click(getByLabelText('Select this row')); + + // Open Actions dropdown and click Duplicate + fireEvent.click(getByText('Actions')); + fireEvent.click(getByText('Duplicate')); + + // Ensure the modal is open (you may need to adjust based on your modal implementation) + expect(getAllByText('Duplicate notebook')).toHaveLength(1); + + // Mock user input and submit + fireEvent.input(getByTestId('custom-input-modal-input'), { + target: { value: 'new-copy' }, + }); + fireEvent.click(getByTestId('custom-input-modal-confirm-button')); + + // Assert that the cloneNotebook function is called + expect(props.cloneNotebook).toHaveBeenCalledTimes(1); + expect(props.cloneNotebook).toHaveBeenCalledWith('new-copy', 'id-1'); + }); + + it('deletes a notebook', () => { + const notebooks = [ + { + path: 'path-1', + id: 'id-1', + dateCreated: 'date-created', + dateModified: 'date-modified', + }, + ]; + const { getByText, getByLabelText, getAllByText, getByTestId } = renderNoteTable({ notebooks }); + + // Select a notebook + fireEvent.click(getByLabelText('Select this row')); + + // Open Actions dropdown and click Delete + fireEvent.click(getByText('Actions')); + fireEvent.click(getByText('Delete')); + + // Ensure the modal is open (you may need to adjust based on your modal implementation) + expect(getAllByText('Delete 1 notebook')).toHaveLength(1); + + // Mock user confirmation and submit + fireEvent.input(getByTestId('delete-notebook-modal-input'), { + target: { value: 'delete' }, + }); + fireEvent.click(getByTestId('delete-notebook-modal-delete-button')); + + // Assert that the deleteNotebook function is called + expect(props.deleteNotebook).toHaveBeenCalledTimes(1); + expect(props.deleteNotebook).toHaveBeenCalledWith(['id-1'], expect.any(String)); + }); + + it('adds sample notebooks', async () => { + const { getByText, getAllByText, getByTestId } = renderNoteTable({ notebooks: [] }); + + // Open Actions dropdown and click Add samples + fireEvent.click(getByText('Actions')); + fireEvent.click(getAllByText('Add samples')[0]); + + // Ensure the modal is open (you may need to adjust based on your modal implementation) + expect(getAllByText('Add sample notebooks')).toHaveLength(1); + + // Mock user confirmation and submit + fireEvent.click(getByTestId('confirmModalConfirmButton')); + + // Assert that the addSampleNotebooks function is called + expect(props.addSampleNotebooks).toHaveBeenCalledTimes(1); + }); + + it('closes the action panel', async () => { + const { getByText, queryByTestId } = renderNoteTable({ notebooks: [] }); + expect(queryByTestId('rename-notebook-btn')).not.toBeInTheDocument(); + + // Open Actions dropdown + fireEvent.click(getByText('Actions')); + + // Ensure the action panel is open + expect(queryByTestId('rename-notebook-btn')).toBeInTheDocument(); + + await act(async () => { + fireEvent.click(getByText('Actions')); + }); + + // Ensure the action panel is closed + expect(queryByTestId('rename-notebook-btn')).not.toBeInTheDocument(); + }); + + it('closes the delete modal', () => { + const notebooks = [ + { + path: 'path-1', + id: 'id-1', + dateCreated: 'date-created', + dateModified: 'date-modified', + }, + ]; + const { getByText, getByLabelText, queryByText } = renderNoteTable({ notebooks }); + + // Select a notebook + fireEvent.click(getByLabelText('Select this row')); + + // Open Actions dropdown and click Delete + fireEvent.click(getByText('Actions')); + fireEvent.click(getByText('Delete')); + + // Ensure the modal is open + expect(getByText('Delete 1 notebook')).toBeInTheDocument(); + + // Close the delete modal + fireEvent.click(getByText('Cancel')); + + // Ensure the delete modal is closed + expect(queryByText('Delete 1 notebook')).toBeNull(); + }); }); diff --git a/public/components/notebooks/components/note_table.tsx b/public/components/notebooks/components/note_table.tsx index 9c63e0008..a25a1d7a6 100644 --- a/public/components/notebooks/components/note_table.tsx +++ b/public/components/notebooks/components/note_table.tsx @@ -36,14 +36,13 @@ import { CREATE_NOTE_MESSAGE, NOTEBOOKS_DOCUMENTATION_URL, } from '../../../../common/constants/notebooks'; -import { UI_DATE_FORMAT } from '../../../../common/constants/shared'; +import { UI_DATE_FORMAT, pageStyles } from '../../../../common/constants/shared'; import { DeleteNotebookModal, getCustomModal, getSampleNotebooksModal, } from './helpers/modal_containers'; import { NotebookType } from './main'; -import { pageStyles } from '../../../../common/constants/shared'; interface NoteTableProps { loading: boolean; @@ -222,6 +221,7 @@ export function NoteTable({ setIsActionsPopoverOpen(false); renameNote(); }} + data-test-subj="rename-notebook-btn" > Rename , @@ -232,6 +232,7 @@ export function NoteTable({ setIsActionsPopoverOpen(false); cloneNote(); }} + data-test-subj="duplicate-notebook-btn" > Duplicate , @@ -242,6 +243,7 @@ export function NoteTable({ setIsActionsPopoverOpen(false); deleteNote(); }} + data-test-subj="delete-notebook-btn" > Delete , @@ -251,6 +253,7 @@ export function NoteTable({ setIsActionsPopoverOpen(false); addSampleNotebooksModal(); }} + data-test-subj="add-samples-btn" > Add samples , From e511c2d82e3a47676bc953d75588a7d2197eaaaa Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Sun, 17 Dec 2023 23:07:43 -0800 Subject: [PATCH 03/14] notebook.tsx test first update Signed-off-by: Shenoy Pratik --- .../__snapshots__/notebook.test.tsx.snap | 49 ++++++++- .../components/__tests__/notebook.test.tsx | 100 +++++++++++++----- .../helpers/__tests__/default_parser.test.tsx | 4 +- .../notebooks/components/notebook.tsx | 25 +++-- .../__tests__/para_input.test.tsx | 2 +- .../__tests__/para_output.test.tsx | 2 +- .../__tests__/paragraphs.test.tsx | 6 +- test/notebooks_constants.ts | 11 ++ .../sampleDefaultNotebooks.tsx | 16 ++- 9 files changed, 169 insertions(+), 46 deletions(-) create mode 100644 test/notebooks_constants.ts rename {public/components/notebooks/components/helpers/__tests__ => test}/sampleDefaultNotebooks.tsx (91%) diff --git a/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap b/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap index 90933ace6..774fd1685 100644 --- a/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap +++ b/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap @@ -374,7 +374,48 @@ exports[` spec renders the empty component 1`] = `
+ > +
+
+
+ +
+
+
+
@@ -418,7 +459,9 @@ exports[` spec renders the empty component 1`] = ` />

+ > + sample-notebook-1 +

@@ -436,7 +479,7 @@ exports[` spec renders the empty component 1`] = ` Created
- Invalid date + 12/14/2023 06:49 PM

diff --git a/public/components/notebooks/components/__tests__/notebook.test.tsx b/public/components/notebooks/components/__tests__/notebook.test.tsx index f31508852..8cd14185b 100644 --- a/public/components/notebooks/components/__tests__/notebook.test.tsx +++ b/public/components/notebooks/components/__tests__/notebook.test.tsx @@ -3,17 +3,19 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { fireEvent, render, waitFor } from '@testing-library/react'; -import { configure, mount, shallow } from 'enzyme'; +import '@testing-library/jest-dom'; +import { act, render, waitFor } from '@testing-library/react'; +import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; -import PPLService from '../../../../services/requests/ppl'; import React from 'react'; import { HttpResponse } from '../../../../../../../src/core/public'; import httpClientMock from '../../../../../test/__mocks__/httpClientMock'; -import { sampleNotebook1 } from '../helpers/__tests__/sampleDefaultNotebooks'; -import { Notebook } from '../notebook'; -import { SavedObjectsActions } from '../../../../services/saved_objects/saved_object_client/saved_objects_actions'; +import { addCodeBlockResponse } from '../../../../../test/notebooks_constants'; import { sampleSavedVisualization } from '../../../../../test/panels_constants'; +import { emptyNotebook, sampleNotebook1 } from '../../../../../test/sampleDefaultNotebooks'; +import PPLService from '../../../../services/requests/ppl'; +import { SavedObjectsActions } from '../../../../services/saved_objects/saved_object_client/saved_objects_actions'; +import { Notebook } from '../notebook'; jest.mock('../../../../../../../src/plugins/embeddable/public', () => ({ ViewMode: { @@ -36,17 +38,19 @@ global.fetch = jest.fn(() => describe(' spec', () => { configure({ adapter: new Adapter() }); + const pplService = new PPLService(httpClientMock); + const setBreadcrumbs = jest.fn(); + const renameNotebook = jest.fn(); + const cloneNotebook = jest.fn(); + const deleteNotebook = jest.fn(); + const setToast = jest.fn(); + const location = jest.fn() as any; + location.search = ''; + const history = jest.fn() as any; + history.replace = jest.fn(); it('renders the empty component', async () => { - const pplService = new PPLService(httpClientMock); - const setBreadcrumbs = jest.fn(); - const renameNotebook = jest.fn(); - const cloneNotebook = jest.fn(); - const deleteNotebook = jest.fn(); - const setToast = jest.fn(); - const location = jest.fn(); - const history = jest.fn() as any; - history.replace = jest.fn(); + httpClientMock.get = jest.fn(() => Promise.resolve((emptyNotebook as unknown) as HttpResponse)); const utils = render( spec', () => { history={history} /> ); + await waitFor(() => { + expect(utils.getByText('sample-notebook-1')).toBeInTheDocument(); + }); expect(utils.container.firstChild).toMatchSnapshot(); - utils.getByText('Add code block').click(); - utils.getByText('Add visualization').click(); }); - it('renders the component', async () => { - const pplService = new PPLService(httpClientMock); - const setBreadcrumbs = jest.fn(); - const renameNotebook = jest.fn(); - const cloneNotebook = jest.fn(); - const deleteNotebook = jest.fn(); - const setToast = jest.fn(); - const location = jest.fn(); - const history = jest.fn() as any; - history.replace = jest.fn(); + it('renders the empty component and checks code block operations', async () => { + httpClientMock.get = jest.fn(() => Promise.resolve((emptyNotebook as unknown) as HttpResponse)); + httpClientMock.post = jest.fn(() => { + console.log('post called'); + return Promise.resolve((addCodeBlockResponse as unknown) as HttpResponse); + }); + const utils = render( + + ); + await waitFor(() => { + expect(utils.getByText('sample-notebook-1')).toBeInTheDocument(); + }); + + act(() => { + utils.getByText('Add code block').click(); + }); + await waitFor(() => { + expect( + utils.getByPlaceholderText( + 'Type %md, %sql or %ppl on the first line to define the input type. Code block starts here.' + ) + ).toBeInTheDocument(); + }); + + act(() => { + utils.getByLabelText('Toggle show input').click(); + }); + + await waitFor(() => { + expect( + utils.queryByPlaceholderText( + 'Type %md, %sql or %ppl on the first line to define the input type. Code block starts here.' + ) + ).toBeNull(); + }); + }); + + it('renders the component', async () => { SavedObjectsActions.getBulk = jest.fn().mockResolvedValue({ observabilityObjectList: [{ savedVisualization: sampleSavedVisualization }], }); diff --git a/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx b/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx index 3c03a3d5b..517f87c71 100644 --- a/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx +++ b/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx @@ -3,7 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { defaultParagraphParser } from '../default_parser'; import { sampleNotebook1, sampleNotebook2, @@ -12,7 +11,8 @@ import { sampleNotebook5, sampleParsedParagraghs1, sampleParsedParagraghs2, -} from './sampleDefaultNotebooks'; +} from '../../../../../../test/sampleDefaultNotebooks'; +import { defaultParagraphParser } from '../default_parser'; // Perfect schema describe('Testing default backend parser function with perfect schema', () => { diff --git a/public/components/notebooks/components/notebook.tsx b/public/components/notebooks/components/notebook.tsx index 4f22f146f..2059bb452 100644 --- a/public/components/notebooks/components/notebook.tsx +++ b/public/components/notebooks/components/notebook.tsx @@ -6,7 +6,7 @@ import { EuiButton, EuiButtonGroup, - EuiButtonGroupOption, + EuiButtonGroupOptionProps, EuiCard, EuiContextMenu, EuiContextMenuPanelDescriptor, @@ -27,7 +27,6 @@ import moment from 'moment'; import queryString from 'query-string'; import React, { Component } from 'react'; import { RouteComponentProps } from 'react-router-dom'; -import PPLService from '../../../services/requests/ppl'; import { ChromeBreadcrumb, CoreStart } from '../../../../../../src/core/public'; import { DashboardStart } from '../../../../../../src/plugins/dashboard/public'; import { @@ -36,6 +35,7 @@ import { } from '../../../../common/constants/notebooks'; import { UI_DATE_FORMAT } from '../../../../common/constants/shared'; import { ParaType } from '../../../../common/types/notebooks'; +import PPLService from '../../../services/requests/ppl'; import { GenerateReportLoadingModal } from './helpers/custom_modals/reporting_loading_modal'; import { defaultParagraphParser } from './helpers/default_parser'; import { DeleteNotebookModal, getCustomModal, getDeleteModal } from './helpers/modal_containers'; @@ -689,7 +689,7 @@ export class Notebook extends Component {

); - const viewOptions: EuiButtonGroupOption[] = [ + const viewOptions: EuiButtonGroupOptionProps[] = [ { id: 'view_both', label: 'View both', @@ -890,7 +890,11 @@ export class Notebook extends Component { id="reportingActionsButton" iconType="arrowDown" iconSide="right" - onClick={() => this.setState({ isReportingActionsPopoverOpen: true })} + onClick={() => + this.setState({ + isReportingActionsPopoverOpen: !this.state.isReportingActionsPopoverOpen, + }) + } > Reporting actions @@ -922,6 +926,7 @@ export class Notebook extends Component { onChange={(id) => { this.updateView(id); }} + legend="notebook view buttons" /> )} @@ -935,7 +940,11 @@ export class Notebook extends Component { data-test-subj="notebook-paragraph-actions-button" iconType="arrowDown" iconSide="right" - onClick={() => this.setState({ isParaActionsPopoverOpen: true })} + onClick={() => + this.setState({ + isParaActionsPopoverOpen: !this.state.isParaActionsPopoverOpen, + }) + } > Paragraph actions @@ -955,7 +964,11 @@ export class Notebook extends Component { data-test-subj="notebook-notebook-actions-button" iconType="arrowDown" iconSide="right" - onClick={() => this.setState({ isNoteActionsPopoverOpen: true })} + onClick={() => + this.setState({ + isNoteActionsPopoverOpen: !this.state.isNoteActionsPopoverOpen, + }) + } > Notebook actions diff --git a/public/components/notebooks/components/paragraph_components/__tests__/para_input.test.tsx b/public/components/notebooks/components/paragraph_components/__tests__/para_input.test.tsx index de07ab37d..ad183024e 100644 --- a/public/components/notebooks/components/paragraph_components/__tests__/para_input.test.tsx +++ b/public/components/notebooks/components/paragraph_components/__tests__/para_input.test.tsx @@ -7,7 +7,7 @@ import { fireEvent, render, waitFor } from '@testing-library/react'; import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; -import { sampleParsedParagraghs1 } from '../../helpers/__tests__/sampleDefaultNotebooks'; +import { sampleParsedParagraghs1 } from '../../../../../../test/sampleDefaultNotebooks'; import { ParaInput } from '../para_input'; describe(' spec', () => { diff --git a/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx b/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx index 3b2d2e9fa..28739f119 100644 --- a/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx +++ b/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx @@ -7,7 +7,7 @@ import { render } from '@testing-library/react'; import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; -import { sampleParsedParagraghs1 } from '../../helpers/__tests__/sampleDefaultNotebooks'; +import { sampleParsedParagraghs1 } from '../../../../../../test/sampleDefaultNotebooks'; import { ParaOutput } from '../para_output'; import { uiSettingsService } from '../../../../../../common/utils/core_services'; diff --git a/public/components/notebooks/components/paragraph_components/__tests__/paragraphs.test.tsx b/public/components/notebooks/components/paragraph_components/__tests__/paragraphs.test.tsx index 710499a99..303cf84de 100644 --- a/public/components/notebooks/components/paragraph_components/__tests__/paragraphs.test.tsx +++ b/public/components/notebooks/components/paragraph_components/__tests__/paragraphs.test.tsx @@ -3,12 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { fireEvent, render } from '@testing-library/react'; -import { configure, mount, shallow } from 'enzyme'; +import { render } from '@testing-library/react'; +import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; import httpClientMock from '../../../../../../test/__mocks__/httpClientMock'; -import { sampleParsedParagraghs1 } from '../../helpers/__tests__/sampleDefaultNotebooks'; +import { sampleParsedParagraghs1 } from '../../../../../../test/sampleDefaultNotebooks'; import { Paragraphs } from '../paragraphs'; jest.mock('../../../../../../../../src/plugins/embeddable/public', () => ({ diff --git a/test/notebooks_constants.ts b/test/notebooks_constants.ts new file mode 100644 index 000000000..8c9e81189 --- /dev/null +++ b/test/notebooks_constants.ts @@ -0,0 +1,11 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ +export const addCodeBlockResponse = { + id: 'paragraph_044d9850-b0b2-4034-8590-6d845c65d1a7', + dateCreated: '2023-12-18T06:27:34.320Z', + dateModified: '2023-12-18T06:27:34.320Z', + input: { inputType: 'MARKDOWN', inputText: '' }, + output: [{ outputType: 'MARKDOWN', result: '', execution_time: '0s' }], +}; diff --git a/public/components/notebooks/components/helpers/__tests__/sampleDefaultNotebooks.tsx b/test/sampleDefaultNotebooks.tsx similarity index 91% rename from public/components/notebooks/components/helpers/__tests__/sampleDefaultNotebooks.tsx rename to test/sampleDefaultNotebooks.tsx index 17e077ed5..0356d3a65 100644 --- a/public/components/notebooks/components/helpers/__tests__/sampleDefaultNotebooks.tsx +++ b/test/sampleDefaultNotebooks.tsx @@ -3,6 +3,13 @@ * SPDX-License-Identifier: Apache-2.0 */ +export const emptyNotebook = { + path: 'sample-notebook-1', + dateCreated: '2023-12-14T18:49:43.375Z', + dateModified: '2023-12-15T06:13:23.463Z', + paragraphs: [], +}; + // Sample notebook with all input and output export const sampleNotebook1 = { id: 'note_5f4b9eed-5898-4b39-ba6c-755c0fadd84e', @@ -119,7 +126,8 @@ export const sampleParsedParagraghs1 = [ vizObjectInput: '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', id: 3, - inp: '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', + inp: + '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', lang: 'text/x-', isInputExpanded: false, isOutputStale: false, @@ -221,7 +229,8 @@ export const sampleParsedParagraghs2 = [ isVizualisation: false, vizObjectInput: '', id: 1, - inp: '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__', + inp: + '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__', lang: 'text/x-md', isInputExpanded: false, isOutputStale: false, @@ -272,7 +281,8 @@ export const sampleParsedParagraghs2 = [ vizObjectInput: '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', id: 3, - inp: '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', + inp: + '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', lang: 'text/x-', isInputExpanded: false, isOutputStale: false, From ae055582cca8e4ccd35fc018b8da6dcc73e38b49 Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Mon, 18 Dec 2023 22:02:12 -0800 Subject: [PATCH 04/14] update paragraph/notebook action tests Signed-off-by: Shenoy Pratik --- .../__snapshots__/notebook.test.tsx.snap | 170 ++++++------ .../components/__tests__/notebook.test.tsx | 242 +++++++++++++++++- .../helpers/__tests__/default_parser.test.tsx | 2 +- .../__tests__/para_input.test.tsx | 2 +- .../__tests__/para_output.test.tsx | 2 +- .../__tests__/paragraphs.test.tsx | 2 +- .../paragraph_components/para_query_grid.tsx | 4 +- test/notebooks_constants.ts | 43 ++++ ...books.tsx => sample_default_notebooks.tsx} | 0 9 files changed, 364 insertions(+), 103 deletions(-) rename test/{sampleDefaultNotebooks.tsx => sample_default_notebooks.tsx} (100%) diff --git a/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap b/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap index 774fd1685..6103f85cf 100644 --- a/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap +++ b/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[` spec renders the component 1`] = ` +exports[` spec renders the empty component 1`] = `
@@ -41,19 +41,14 @@ exports[` spec renders the component 1`] = ` > + /> @@ -66,7 +61,48 @@ exports[` spec renders the component 1`] = `
+ > +
+
+
+ +
+
+
+
@@ -86,19 +122,14 @@ exports[` spec renders the component 1`] = ` > + /> @@ -115,7 +146,9 @@ exports[` spec renders the component 1`] = ` />

+ > + sample-notebook-1 +

@@ -133,7 +166,7 @@ exports[` spec renders the component 1`] = ` Created
- Invalid date + 12/14/2023 06:49 PM

@@ -184,18 +217,14 @@ exports[` spec renders the component 1`] = ` > + />
spec renders the component 1`] = ` > + />
spec renders the component 1`] = `
`; -exports[` spec renders the empty component 1`] = ` +exports[` spec renders the visualization component 1`] = `
@@ -354,14 +379,19 @@ exports[` spec renders the empty component 1`] = ` > + > + + @@ -374,48 +404,7 @@ exports[` spec renders the empty component 1`] = `
-
-
-
- -
-
-
-
+ />
@@ -435,14 +424,19 @@ exports[` spec renders the empty component 1`] = ` > + > + + @@ -459,9 +453,7 @@ exports[` spec renders the empty component 1`] = ` />

- sample-notebook-1 -

+ />
@@ -479,7 +471,7 @@ exports[` spec renders the empty component 1`] = ` Created
- 12/14/2023 06:49 PM + Invalid date

@@ -530,14 +522,18 @@ exports[` spec renders the empty component 1`] = ` > + > + +
spec renders the empty component 1`] = ` > + > + +
spec', () => { it('renders the empty component and checks code block operations', async () => { httpClientMock.get = jest.fn(() => Promise.resolve((emptyNotebook as unknown) as HttpResponse)); + let postFlag = 1; httpClientMock.post = jest.fn(() => { - console.log('post called'); - return Promise.resolve((addCodeBlockResponse as unknown) as HttpResponse); + if (postFlag === 1) { + postFlag += 1; + return Promise.resolve((addCodeBlockResponse as unknown) as HttpResponse); + } else return Promise.resolve((runCodeBlockResponse as unknown) as HttpResponse); }); const utils = render( spec', () => { utils.getByText('Add code block').click(); }); + await waitFor(() => { + expect(utils.getByPlaceholderText(codePlaceholderText)).toBeInTheDocument(); + }); + + act(() => { + utils.getByLabelText('Toggle show input').click(); + }); + + await waitFor(() => { + expect(utils.queryByPlaceholderText(codePlaceholderText)).toBeNull(); + }); + + act(() => { + utils.getByLabelText('Toggle show input').click(); + }); + + act(() => { + fireEvent.input(utils.getByPlaceholderText(codePlaceholderText), { + target: { value: '%md \\n hello' }, + }); + fireEvent.click(utils.getByText('Run')); + }); + + await waitFor(() => { + expect(utils.queryByText('Run')).toBeNull(); + expect(utils.getByText('hello')).toBeInTheDocument(); + }); + + act(() => { + fireEvent.click(utils.getByTestId('input_only')); + }); + + await waitFor(() => { + expect(utils.queryByText('Refresh')).toBeInTheDocument(); + }); + + act(() => { + fireEvent.click(utils.getByTestId('output_only')); + }); + + await waitFor(() => { + expect(utils.queryByText('Refresh')).toBeNull(); + expect(utils.getByText('hello')).toBeInTheDocument(); + }); + }); + + it('renders a notebook and checks paragraph actions', async () => { + httpClientMock.get = jest.fn(() => + Promise.resolve((codeBlockNotebook as unknown) as HttpResponse) + ); + httpClientMock.put = jest.fn(() => + Promise.resolve((clearOutputNotebook as unknown) as HttpResponse) + ); + httpClientMock.delete = jest.fn(() => + Promise.resolve(({ paragraphs: [] } as unknown) as HttpResponse) + ); + + const utils = render( + + ); + await waitFor(() => { + expect(utils.getByText('sample-notebook-1')).toBeInTheDocument(); + }); + + act(() => { + fireEvent.click(utils.getByText('Paragraph actions')); + }); + + act(() => { + fireEvent.click(utils.getByText('Clear all outputs')); + }); + await waitFor(() => { expect( - utils.getByPlaceholderText( - 'Type %md, %sql or %ppl on the first line to define the input type. Code block starts here.' + utils.queryByText( + 'Are you sure you want to clear all outputs? The action cannot be undone.' ) ).toBeInTheDocument(); }); act(() => { - utils.getByLabelText('Toggle show input').click(); + fireEvent.click(utils.getByTestId('confirmModalConfirmButton')); + }); + + await waitFor(() => { + expect(utils.queryByText('hello')).toBeNull(); + }); + + act(() => { + fireEvent.click(utils.getByText('Paragraph actions')); + }); + + act(() => { + fireEvent.click(utils.getByText('Delete all paragraphs')); }); await waitFor(() => { expect( - utils.queryByPlaceholderText( - 'Type %md, %sql or %ppl on the first line to define the input type. Code block starts here.' + utils.queryByText( + 'Are you sure you want to delete all paragraphs? The action cannot be undone.' ) - ).toBeNull(); + ).toBeInTheDocument(); }); + + act(() => { + fireEvent.click(utils.getByTestId('confirmModalConfirmButton')); + }); + + await waitFor(() => { + expect(utils.queryByText('No paragraphs')).toBeInTheDocument(); + }); + }); + + it('renders a notebook and checks notebook actions', async () => { + const renameNotebookMock = jest.fn(() => + Promise.resolve((notebookPutResponse as unknown) as HttpResponse) + ); + const cloneNotebookMock = jest.fn(() => Promise.resolve('dummy-string')); + httpClientMock.get = jest.fn(() => + Promise.resolve((codeBlockNotebook as unknown) as HttpResponse) + ); + + httpClientMock.put = jest.fn(() => { + return Promise.resolve((notebookPutResponse as unknown) as HttpResponse); + }); + + httpClientMock.post = jest.fn(() => { + return Promise.resolve((addCodeBlockResponse as unknown) as HttpResponse); + }); + + const utils = render( + + ); + await waitFor(() => { + expect(utils.getByText('sample-notebook-1')).toBeInTheDocument(); + }); + + act(() => { + fireEvent.click(utils.getByText('Notebook actions')); + }); + + act(() => { + fireEvent.click(utils.getByText('Rename notebook')); + }); + + await waitFor(() => { + expect(utils.queryByTestId('custom-input-modal-input')).toBeInTheDocument(); + }); + + act(() => { + fireEvent.input(utils.getByTestId('custom-input-modal-input'), { + target: { value: 'test-notebook-newname' }, + }); + fireEvent.click(utils.getByTestId('custom-input-modal-confirm-button')); + }); + + await waitFor(() => { + expect(renameNotebookMock).toHaveBeenCalledTimes(1); + }); + + act(() => { + fireEvent.click(utils.getByText('Notebook actions')); + }); + + act(() => { + fireEvent.click(utils.getByText('Duplicate notebook')); + }); + + await waitFor(() => { + expect(utils.queryByTestId('custom-input-modal-input')).toBeInTheDocument(); + }); + + act(() => { + fireEvent.click(utils.getByTestId('custom-input-modal-confirm-button')); + }); + + expect(cloneNotebookMock).toHaveBeenCalledTimes(1); + + act(() => { + fireEvent.click(utils.getByText('Notebook actions')); + }); + + act(() => { + fireEvent.click(utils.getByText('Delete notebook')); + }); + + await waitFor(() => { + expect(utils.queryByTestId('delete-notebook-modal-input')).toBeInTheDocument(); + }); + + act(() => { + fireEvent.input(utils.getByTestId('delete-notebook-modal-input'), { + target: { value: 'delete' }, + }); + }); + + act(() => { + fireEvent.click(utils.getByTestId('delete-notebook-modal-delete-button')); + }); + + expect(deleteNotebook).toHaveBeenCalledTimes(1); }); - it('renders the component', async () => { + it('renders the visualization component', async () => { SavedObjectsActions.getBulk = jest.fn().mockResolvedValue({ observabilityObjectList: [{ savedVisualization: sampleSavedVisualization }], }); diff --git a/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx b/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx index 517f87c71..fdcabaa00 100644 --- a/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx +++ b/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx @@ -11,7 +11,7 @@ import { sampleNotebook5, sampleParsedParagraghs1, sampleParsedParagraghs2, -} from '../../../../../../test/sampleDefaultNotebooks'; +} from '../../../../../../test/sample_default_notebooks'; import { defaultParagraphParser } from '../default_parser'; // Perfect schema diff --git a/public/components/notebooks/components/paragraph_components/__tests__/para_input.test.tsx b/public/components/notebooks/components/paragraph_components/__tests__/para_input.test.tsx index ad183024e..112326e1e 100644 --- a/public/components/notebooks/components/paragraph_components/__tests__/para_input.test.tsx +++ b/public/components/notebooks/components/paragraph_components/__tests__/para_input.test.tsx @@ -7,7 +7,7 @@ import { fireEvent, render, waitFor } from '@testing-library/react'; import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; -import { sampleParsedParagraghs1 } from '../../../../../../test/sampleDefaultNotebooks'; +import { sampleParsedParagraghs1 } from '../../../../../../test/sample_default_notebooks'; import { ParaInput } from '../para_input'; describe(' spec', () => { diff --git a/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx b/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx index 28739f119..f3918ac35 100644 --- a/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx +++ b/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx @@ -7,7 +7,7 @@ import { render } from '@testing-library/react'; import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; -import { sampleParsedParagraghs1 } from '../../../../../../test/sampleDefaultNotebooks'; +import { sampleParsedParagraghs1 } from '../../../../../../test/sample_default_notebooks'; import { ParaOutput } from '../para_output'; import { uiSettingsService } from '../../../../../../common/utils/core_services'; diff --git a/public/components/notebooks/components/paragraph_components/__tests__/paragraphs.test.tsx b/public/components/notebooks/components/paragraph_components/__tests__/paragraphs.test.tsx index 303cf84de..381463f88 100644 --- a/public/components/notebooks/components/paragraph_components/__tests__/paragraphs.test.tsx +++ b/public/components/notebooks/components/paragraph_components/__tests__/paragraphs.test.tsx @@ -8,7 +8,7 @@ import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; import httpClientMock from '../../../../../../test/__mocks__/httpClientMock'; -import { sampleParsedParagraghs1 } from '../../../../../../test/sampleDefaultNotebooks'; +import { sampleParsedParagraghs1 } from '../../../../../../test/sample_default_notebooks'; import { Paragraphs } from '../paragraphs'; jest.mock('../../../../../../../../src/plugins/embeddable/public', () => ({ diff --git a/public/components/notebooks/components/paragraph_components/para_query_grid.tsx b/public/components/notebooks/components/paragraph_components/para_query_grid.tsx index 6321c5702..87e63845a 100644 --- a/public/components/notebooks/components/paragraph_components/para_query_grid.tsx +++ b/public/components/notebooks/components/paragraph_components/para_query_grid.tsx @@ -3,9 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import $ from 'jquery'; import { EuiDataGrid, EuiLoadingSpinner, EuiSpacer } from '@elastic/eui'; +import $ from 'jquery'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; interface QueryDataGridProps { rowCount: number; diff --git a/test/notebooks_constants.ts b/test/notebooks_constants.ts index 8c9e81189..6075a8107 100644 --- a/test/notebooks_constants.ts +++ b/test/notebooks_constants.ts @@ -9,3 +9,46 @@ export const addCodeBlockResponse = { input: { inputType: 'MARKDOWN', inputText: '' }, output: [{ outputType: 'MARKDOWN', result: '', execution_time: '0s' }], }; + +export const runCodeBlockResponse = { + output: [{ outputType: 'MARKDOWN', result: '\n\nhello', execution_time: '0.939 ms' }], + input: { inputText: '%md \n\nhello', inputType: 'MARKDOWN' }, + dateCreated: '2023-12-18T22:13:39.627Z', + dateModified: '2023-12-18T22:17:24.853Z', + id: 'paragraph_7713f4d5-c3b2-406d-9f06-99a1fe0251f3', +}; + +export const codePlaceholderText = + 'Type %md, %sql or %ppl on the first line to define the input type. Code block starts here.'; + +export const codeBlockNotebook = { + path: 'sample-notebook-1', + dateCreated: '2023-12-14T18:49:43.375Z', + dateModified: '2023-12-18T23:40:59.500Z', + paragraphs: [ + { + output: [{ result: 'hello', outputType: 'MARKDOWN', execution_time: '0.018 ms' }], + input: { inputText: '%md\nhello', inputType: 'MARKDOWN' }, + dateCreated: '2023-12-18T23:38:50.848Z', + dateModified: '2023-12-18T23:39:12.265Z', + id: 'paragraph_de00ea2d-a8fb-45d1-8085-698f51c6b6be', + }, + ], +}; + +export const clearOutputNotebook = { + paragraphs: [ + { + output: [], + input: { inputText: '%md\nhello', inputType: 'MARKDOWN' }, + dateCreated: '2023-12-18T23:38:50.848Z', + dateModified: '2023-12-18T23:39:12.265Z', + id: 'paragraph_de00ea2d-a8fb-45d1-8085-698f51c6b6be', + }, + ], +}; + +export const notebookPutResponse = { + status: 'OK', + message: { objectId: '69CpaYwBKIZhlDIhx-OK' }, +}; diff --git a/test/sampleDefaultNotebooks.tsx b/test/sample_default_notebooks.tsx similarity index 100% rename from test/sampleDefaultNotebooks.tsx rename to test/sample_default_notebooks.tsx From 8fcfd036ac654911c8eb0e45618306dc961d634f Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Wed, 3 Jan 2024 14:55:07 -0800 Subject: [PATCH 05/14] lint fixes Signed-off-by: Shenoy Pratik --- .../paragraph_components/para_output.tsx | 4 +-- .../paragraph_components/para_query_grid.tsx | 26 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/public/components/notebooks/components/paragraph_components/para_output.tsx b/public/components/notebooks/components/paragraph_components/para_output.tsx index 44af810b4..7bc09c843 100644 --- a/public/components/notebooks/components/paragraph_components/para_output.tsx +++ b/public/components/notebooks/components/paragraph_components/para_output.tsx @@ -91,7 +91,7 @@ const OutputBody = ({ setVisibleColumns(columns.map(({ id }) => id)); return (
- + {inputQuery} @@ -108,7 +108,7 @@ const OutputBody = ({ } case 'MARKDOWN': return ( - + ); diff --git a/public/components/notebooks/components/paragraph_components/para_query_grid.tsx b/public/components/notebooks/components/paragraph_components/para_query_grid.tsx index 87e63845a..834cd2c87 100644 --- a/public/components/notebooks/components/paragraph_components/para_query_grid.tsx +++ b/public/components/notebooks/components/paragraph_components/para_query_grid.tsx @@ -10,6 +10,8 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; interface QueryDataGridProps { rowCount: number; queryColumns: any[]; + visibleColumns: any[]; + setVisibleColumns: (visibleColumns: string[]) => void; dataValues: any[]; } @@ -19,25 +21,23 @@ interface RenderCellValueProps { } function QueryDataGrid(props: QueryDataGridProps) { - const { rowCount, queryColumns, dataValues } = props; + const { rowCount, queryColumns, visibleColumns, setVisibleColumns, dataValues } = props; const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 }); // ** Sorting config const [sortingColumns, setSortingColumns] = useState([]); - const [visibleColumns, setVisibleColumns] = useState>([]); - const [isVisible, setIsVisible] = useState(false); const onSort = useCallback( - (newColumns) => { - setSortingColumns(newColumns); + (sortColumns) => { + setSortingColumns(sortColumns); }, [setSortingColumns] ); const onChangeItemsPerPage = useCallback( (pageSize) => - setPagination((newPagination) => ({ - ...newPagination, + setPagination((paginate) => ({ + ...paginate, pageSize, pageIndex: 0, })), @@ -45,7 +45,7 @@ function QueryDataGrid(props: QueryDataGridProps) { ); const onChangePage = useCallback( - (pageIndex) => setPagination((newPagination) => ({ ...newPagination, pageIndex })), + (pageIndex) => setPagination((paginate) => ({ ...paginate, pageIndex })), [setPagination] ); @@ -55,10 +55,10 @@ function QueryDataGrid(props: QueryDataGridProps) { }; }, []); - const getUpdatedVisibleColumns = () => { + const getUpdatedVisibleColumns = (queryCols: any[]) => { const updatedVisibleColumns = []; - for (let index = 0; index < queryColumns.length; ++index) { - updatedVisibleColumns.push(queryColumns[index].displayAsText); + for (let index = 0; index < queryCols.length; ++index) { + updatedVisibleColumns.push(queryCols[index].displayAsText); } return updatedVisibleColumns; }; @@ -72,8 +72,8 @@ function QueryDataGrid(props: QueryDataGridProps) { setIsVisible(true); } }, 1000); - setVisibleColumns(getUpdatedVisibleColumns()); - }, []); + setVisibleColumns(getUpdatedVisibleColumns(queryColumns)); + }, [queryColumns, setVisibleColumns]); const displayLoadingSpinner = !isVisible ? ( <> From 670270df3aa996b9daa76d2307d01e248805a41d Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Wed, 3 Jan 2024 15:39:28 -0800 Subject: [PATCH 06/14] updating paragraph components Signed-off-by: Shenoy Pratik --- .../paragraph_components/para_output.tsx | 6 +---- .../paragraph_components/para_query_grid.tsx | 27 +++++++++---------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/public/components/notebooks/components/paragraph_components/para_output.tsx b/public/components/notebooks/components/paragraph_components/para_output.tsx index 7bc09c843..6fee9c66c 100644 --- a/public/components/notebooks/components/paragraph_components/para_output.tsx +++ b/public/components/notebooks/components/paragraph_components/para_output.tsx @@ -7,7 +7,7 @@ import { EuiCodeBlock, EuiSpacer, EuiText } from '@elastic/eui'; import MarkdownRender from '@nteract/markdown'; import { Media } from '@nteract/outputs'; import moment from 'moment'; -import React, { useState } from 'react'; +import React from 'react'; import { CoreStart } from '../../../../../../../src/core/public'; import { DashboardContainerInput, @@ -76,7 +76,6 @@ const OutputBody = ({ */ const dateFormat = uiSettingsService.get('dateFormat'); - const [visibleColumns, setVisibleColumns] = useState([]); if (typeOut !== undefined) { switch (typeOut) { @@ -88,7 +87,6 @@ const OutputBody = ({ } else { const columns = createQueryColumns(queryObject.schema); const data = getQueryOutputData(queryObject); - setVisibleColumns(columns.map(({ id }) => id)); return (
@@ -99,8 +97,6 @@ const OutputBody = ({ key={key} rowCount={queryObject.datarows.length} queryColumns={columns} - visibleColumns={visibleColumns} - setVisibleColumns={setVisibleColumns} dataValues={data} />
diff --git a/public/components/notebooks/components/paragraph_components/para_query_grid.tsx b/public/components/notebooks/components/paragraph_components/para_query_grid.tsx index 834cd2c87..28b986076 100644 --- a/public/components/notebooks/components/paragraph_components/para_query_grid.tsx +++ b/public/components/notebooks/components/paragraph_components/para_query_grid.tsx @@ -10,8 +10,6 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; interface QueryDataGridProps { rowCount: number; queryColumns: any[]; - visibleColumns: any[]; - setVisibleColumns: (visibleColumns: string[]) => void; dataValues: any[]; } @@ -21,23 +19,25 @@ interface RenderCellValueProps { } function QueryDataGrid(props: QueryDataGridProps) { - const { rowCount, queryColumns, visibleColumns, setVisibleColumns, dataValues } = props; + const { rowCount, queryColumns, dataValues } = props; const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 }); // ** Sorting config const [sortingColumns, setSortingColumns] = useState([]); + const [visibleColumns, setVisibleColumns] = useState([]); + const [isVisible, setIsVisible] = useState(false); const onSort = useCallback( - (sortColumns) => { - setSortingColumns(sortColumns); + (newColumns) => { + setSortingColumns(newColumns); }, [setSortingColumns] ); const onChangeItemsPerPage = useCallback( (pageSize) => - setPagination((paginate) => ({ - ...paginate, + setPagination((newPagination) => ({ + ...newPagination, pageSize, pageIndex: 0, })), @@ -45,7 +45,7 @@ function QueryDataGrid(props: QueryDataGridProps) { ); const onChangePage = useCallback( - (pageIndex) => setPagination((paginate) => ({ ...paginate, pageIndex })), + (pageIndex) => setPagination((newPagination) => ({ ...newPagination, pageIndex })), [setPagination] ); @@ -55,10 +55,10 @@ function QueryDataGrid(props: QueryDataGridProps) { }; }, []); - const getUpdatedVisibleColumns = (queryCols: any[]) => { + const getUpdatedVisibleColumns = () => { const updatedVisibleColumns = []; - for (let index = 0; index < queryCols.length; ++index) { - updatedVisibleColumns.push(queryCols[index].displayAsText); + for (let index = 0; index < queryColumns.length; ++index) { + updatedVisibleColumns.push(queryColumns[index].displayAsText); } return updatedVisibleColumns; }; @@ -72,8 +72,8 @@ function QueryDataGrid(props: QueryDataGridProps) { setIsVisible(true); } }, 1000); - setVisibleColumns(getUpdatedVisibleColumns(queryColumns)); - }, [queryColumns, setVisibleColumns]); + setVisibleColumns(getUpdatedVisibleColumns()); + }, []); const displayLoadingSpinner = !isVisible ? ( <> @@ -108,7 +108,6 @@ function queryDataGridPropsAreEqual(prevProps: QueryDataGridProps, nextProps: Qu return ( prevProps.rowCount === nextProps.rowCount && JSON.stringify(prevProps.queryColumns) === JSON.stringify(nextProps.queryColumns) && - JSON.stringify(prevProps.visibleColumns) === JSON.stringify(nextProps.visibleColumns) && JSON.stringify(prevProps.dataValues) === JSON.stringify(nextProps.dataValues) ); } From 1f336bb47c713a6eef4f518e873526d610662ec0 Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Wed, 3 Jan 2024 16:40:24 -0800 Subject: [PATCH 07/14] add test for rendering error in query Signed-off-by: Shenoy Pratik --- .../__snapshots__/para_output.test.tsx.snap | 17 +++++++++++++++++ .../__tests__/para_output.test.tsx | 19 ++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_output.test.tsx.snap b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_output.test.tsx.snap index e8c496b7c..0853177f7 100644 --- a/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_output.test.tsx.snap +++ b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_output.test.tsx.snap @@ -67,6 +67,23 @@ exports[` spec renders query outputs 1`] = `
`; +exports[` spec renders query outputs with error 1`] = ` +
+
+    
+      {"error":"Invalid SQL query"}
+    
+  
+
+`; + exports[` spec renders visualization outputs 1`] = `
spec', () => { configure({ adapter: new Adapter() }); @@ -46,6 +46,23 @@ describe(' spec', () => { expect(utils.container.firstChild).toMatchSnapshot(); }); + it('renders query outputs with error', () => { + const para = sampleParsedParagraghs1[3]; + para.out = ['{"error":"Invalid SQL query"}']; + para.isSelected = true; + const setVisInput = jest.fn(); + const utils = render( + + ); + expect(utils.container.firstChild).toMatchSnapshot(); + }); + it('renders visualization outputs', () => { const para = sampleParsedParagraghs1[2]; para.isSelected = true; From de5cf4177aa509f5828e3d8bfa0dfb17fe27e060 Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Thu, 4 Jan 2024 16:14:53 -0800 Subject: [PATCH 08/14] snapshot updates and adding missing tests Signed-off-by: Shenoy Pratik --- .../__snapshots__/notebook.test.tsx.snap | 2 +- .../components/__tests__/notebook.test.tsx | 55 +++++++++++-------- .../notebooks/components/notebook.tsx | 23 +++++--- .../__snapshots__/para_output.test.tsx.snap | 27 ++++++--- .../__tests__/para_output.test.tsx | 43 ++++++++++++++- test/sample_default_notebooks.tsx | 27 +++++++++ 6 files changed, 135 insertions(+), 42 deletions(-) diff --git a/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap b/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap index 6103f85cf..deb0475bc 100644 --- a/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap +++ b/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[` spec renders the empty component 1`] = ` +exports[` spec renders the empty component and test reporting action button 1`] = `
diff --git a/public/components/notebooks/components/__tests__/notebook.test.tsx b/public/components/notebooks/components/__tests__/notebook.test.tsx index 08520bc76..e0462821a 100644 --- a/public/components/notebooks/components/__tests__/notebook.test.tsx +++ b/public/components/notebooks/components/__tests__/notebook.test.tsx @@ -9,7 +9,7 @@ import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; import { HttpResponse } from '../../../../../../../src/core/public'; -import httpClientMock from '../../../../../test/__mocks__/httpClientMock'; +import { getOSDHttp } from '../../../../../common/utils'; import { addCodeBlockResponse, clearOutputNotebook, @@ -45,7 +45,8 @@ global.fetch = jest.fn(() => describe(' spec', () => { configure({ adapter: new Adapter() }); - const pplService = new PPLService(httpClientMock); + const httpClient = getOSDHttp(); + const pplService = new PPLService(httpClient); const setBreadcrumbs = jest.fn(); const renameNotebook = jest.fn(); const cloneNotebook = jest.fn(); @@ -56,14 +57,14 @@ describe(' spec', () => { const history = jest.fn() as any; history.replace = jest.fn(); - it('renders the empty component', async () => { - httpClientMock.get = jest.fn(() => Promise.resolve((emptyNotebook as unknown) as HttpResponse)); + it('renders the empty component and test reporting action button', async () => { + httpClient.get = jest.fn(() => Promise.resolve((emptyNotebook as unknown) as HttpResponse)); const utils = render( spec', () => { expect(utils.getByText('sample-notebook-1')).toBeInTheDocument(); }); expect(utils.container.firstChild).toMatchSnapshot(); + + act(() => { + fireEvent.click(utils.getByText('Reporting actions')); + }); + + expect(utils.queryByTestId('download-notebook-pdf')).toBeInTheDocument(); + + act(() => { + fireEvent.click(utils.getByText('Reporting actions')); + }); + + await waitFor(() => { + expect(utils.queryByTestId('download-notebook-pdf')).toBeNull(); + }); }); it('renders the empty component and checks code block operations', async () => { - httpClientMock.get = jest.fn(() => Promise.resolve((emptyNotebook as unknown) as HttpResponse)); + httpClient.get = jest.fn(() => Promise.resolve((emptyNotebook as unknown) as HttpResponse)); let postFlag = 1; - httpClientMock.post = jest.fn(() => { + httpClient.post = jest.fn(() => { if (postFlag === 1) { postFlag += 1; return Promise.resolve((addCodeBlockResponse as unknown) as HttpResponse); @@ -94,7 +109,7 @@ describe(' spec', () => { pplService={pplService} openedNoteId="mock-id" DashboardContainerByValueRenderer={jest.fn()} - http={httpClientMock} + http={httpClient} parentBreadcrumb={{ href: 'parent-href', text: 'parent-text' }} setBreadcrumbs={setBreadcrumbs} renameNotebook={renameNotebook} @@ -160,13 +175,11 @@ describe(' spec', () => { }); it('renders a notebook and checks paragraph actions', async () => { - httpClientMock.get = jest.fn(() => - Promise.resolve((codeBlockNotebook as unknown) as HttpResponse) - ); - httpClientMock.put = jest.fn(() => + httpClient.get = jest.fn(() => Promise.resolve((codeBlockNotebook as unknown) as HttpResponse)); + httpClient.put = jest.fn(() => Promise.resolve((clearOutputNotebook as unknown) as HttpResponse) ); - httpClientMock.delete = jest.fn(() => + httpClient.delete = jest.fn(() => Promise.resolve(({ paragraphs: [] } as unknown) as HttpResponse) ); @@ -175,7 +188,7 @@ describe(' spec', () => { pplService={pplService} openedNoteId="mock-id" DashboardContainerByValueRenderer={jest.fn()} - http={httpClientMock} + http={httpClient} parentBreadcrumb={{ href: 'parent-href', text: 'parent-text' }} setBreadcrumbs={setBreadcrumbs} renameNotebook={renameNotebook} @@ -244,15 +257,13 @@ describe(' spec', () => { Promise.resolve((notebookPutResponse as unknown) as HttpResponse) ); const cloneNotebookMock = jest.fn(() => Promise.resolve('dummy-string')); - httpClientMock.get = jest.fn(() => - Promise.resolve((codeBlockNotebook as unknown) as HttpResponse) - ); + httpClient.get = jest.fn(() => Promise.resolve((codeBlockNotebook as unknown) as HttpResponse)); - httpClientMock.put = jest.fn(() => { + httpClient.put = jest.fn(() => { return Promise.resolve((notebookPutResponse as unknown) as HttpResponse); }); - httpClientMock.post = jest.fn(() => { + httpClient.post = jest.fn(() => { return Promise.resolve((addCodeBlockResponse as unknown) as HttpResponse); }); @@ -261,7 +272,7 @@ describe(' spec', () => { pplService={pplService} openedNoteId="mock-id" DashboardContainerByValueRenderer={jest.fn()} - http={httpClientMock} + http={httpClient} parentBreadcrumb={{ href: 'parent-href', text: 'parent-text' }} setBreadcrumbs={setBreadcrumbs} renameNotebook={renameNotebookMock} @@ -347,7 +358,7 @@ describe(' spec', () => { observabilityObjectList: [{ savedVisualization: sampleSavedVisualization }], }); - httpClientMock.get = jest.fn(() => + httpClient.get = jest.fn(() => Promise.resolve(({ ...sampleNotebook1, path: sampleNotebook1.name, @@ -372,7 +383,7 @@ describe(' spec', () => { pplService={pplService} openedNoteId={sampleNotebook1.id} DashboardContainerByValueRenderer={jest.fn()} - http={httpClientMock} + http={httpClient} parentBreadcrumb={{ href: 'parent-href', text: 'parent-text' }} setBreadcrumbs={setBreadcrumbs} renameNotebook={renameNotebook} diff --git a/public/components/notebooks/components/notebook.tsx b/public/components/notebooks/components/notebook.tsx index 2059bb452..9db011412 100644 --- a/public/components/notebooks/components/notebook.tsx +++ b/public/components/notebooks/components/notebook.tsx @@ -193,7 +193,7 @@ export class Notebook extends Component { paragraphId: para.uniqueId, }, }) - .then((res) => { + .then((_res) => { const paragraphs = [...this.state.paragraphs]; paragraphs.splice(index, 1); const parsedPara = [...this.state.parsedPara]; @@ -205,6 +205,7 @@ export class Notebook extends Component { 'Error deleting paragraph, please make sure you have the correct permission.', 'danger' ); + console.error(err); }); } }; @@ -246,6 +247,7 @@ export class Notebook extends Component { 'Error deleting paragraph, please make sure you have the correct permission.', 'danger' ); + console.error(err); }); }, 'Delete all paragraphs', @@ -354,6 +356,7 @@ export class Notebook extends Component { 'Error deleting visualization, please make sure you have the correct permission.', 'danger' ); + console.error(err); }); }; @@ -388,6 +391,7 @@ export class Notebook extends Component { 'Error adding paragraph, please make sure you have the correct permission.', 'danger' ); + console.error(err); }); }; @@ -421,13 +425,14 @@ export class Notebook extends Component { .post(`${NOTEBOOKS_API_PREFIX}/set_paragraphs/`, { body: JSON.stringify(moveParaObj), }) - .then((res) => this.setState({ paragraphs, parsedPara })) - .then((res) => this.scrollToPara(targetIndex)) + .then((_res) => this.setState({ paragraphs, parsedPara })) + .then((_res) => this.scrollToPara(targetIndex)) .catch((err) => { this.props.setToast( 'Error moving paragraphs, please make sure you have the correct permission.', 'danger' ); + console.error(err); }); }; @@ -460,6 +465,7 @@ export class Notebook extends Component { 'Error clearing paragraphs, please make sure you have the correct permission.', 'danger' ); + console.error(err); }); }; @@ -530,9 +536,9 @@ export class Notebook extends Component { } }; - runForAllParagraphs = (reducer: (para: ParaType, index: number) => Promise) => { + runForAllParagraphs = (reducer: (para: ParaType, _index: number) => Promise) => { return this.state.parsedPara - .map((para: ParaType, index: number) => () => reducer(para, index)) + .map((para: ParaType, _index: number) => () => reducer(para, _index)) .reduce((chain, func) => chain.then(func), Promise.resolve()); }; @@ -588,6 +594,7 @@ export class Notebook extends Component { 'Error fetching notebooks, please make sure you have the correct permission.', 'danger' ); + console.error(err); }); }; @@ -604,6 +611,7 @@ export class Notebook extends Component { }) .catch((err) => { this.props.setToast('Error getting query output', 'danger'); + console.error(err); }); }; @@ -655,6 +663,7 @@ export class Notebook extends Component { }) .catch((error) => { this.props.setToast('Error checking Reporting Plugin Installation status.', 'danger'); + console.error(error); }); } @@ -743,7 +752,7 @@ export class Notebook extends Component { disabled: this.state.parsedPara.length === 0, onClick: () => { this.setState({ isParaActionsPopoverOpen: false }); - this.runForAllParagraphs((para: ParaType, index: number) => { + this.runForAllParagraphs((para: ParaType, _index: number) => { return para.paraRef.current?.runParagraph(); }); if (this.state.selectedViewId === 'input_only') { @@ -847,7 +856,7 @@ export class Notebook extends Component { items: [ { name: 'Download PDF', - icon: , + icon: , onClick: () => { this.setState({ isReportingActionsPopoverOpen: false }); generateInContextReport('pdf', this.props, this.toggleReportingLoadingModal); diff --git a/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_output.test.tsx.snap b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_output.test.tsx.snap index 0853177f7..029f9e027 100644 --- a/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_output.test.tsx.snap +++ b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_output.test.tsx.snap @@ -1,5 +1,14 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[` spec renders dashboards visualization outputs 1`] = ` +
+ 2020-Jul-21 18:37:44 - 2020-Aug-20 18:37:44 +
+`; + exports[` spec renders markdown outputs 1`] = `
spec renders markdown outputs 1`] = `
`; +exports[` spec renders observability visualization outputs 1`] = ` +
+ 2020-Jul-21 18:37:44 - 2020-Aug-20 18:37:44 +
+`; + exports[` spec renders other types of outputs 1`] = `
spec renders query outputs with error 1`] = `
`; - -exports[` spec renders visualization outputs 1`] = ` -
- 2020-Jul-21 18:37:44 - 2020-Aug-20 18:37:44 -
-`; diff --git a/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx b/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx index 5dcb8a34d..c19ebd2c6 100644 --- a/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx +++ b/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx @@ -3,16 +3,29 @@ * SPDX-License-Identifier: Apache-2.0 */ +jest.mock('../../../../../test/__mocks__/httpClientMock'); import { render } from '@testing-library/react'; import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; -import { uiSettingsService } from '../../../../../../common/utils/core_services'; -import { sampleParsedParagraghs1 } from '../../../../../../test/sample_default_notebooks'; +import { Provider } from 'react-redux'; +import { legacy_createStore as createStore } from 'redux'; +import { + getOSDHttp, + setPPLService, + uiSettingsService, +} from '../../../../../../common/utils/core_services'; +import { + sampleObservabilityVizParagraph, + sampleParsedParagraghs1, +} from '../../../../../../test/sample_default_notebooks'; +import { rootReducer } from '../../../../../framework/redux/reducers'; +import PPLService from '../../../../../services/requests/ppl'; import { ParaOutput } from '../para_output'; describe(' spec', () => { configure({ adapter: new Adapter() }); + const store = createStore(rootReducer); it('renders markdown outputs', () => { const para = sampleParsedParagraghs1[0]; @@ -63,7 +76,7 @@ describe(' spec', () => { expect(utils.container.firstChild).toMatchSnapshot(); }); - it('renders visualization outputs', () => { + it('renders dashboards visualization outputs', () => { const para = sampleParsedParagraghs1[2]; para.isSelected = true; @@ -84,6 +97,30 @@ describe(' spec', () => { expect(utils.container.firstChild).toMatchSnapshot(); }); + it('renders observability visualization outputs', () => { + setPPLService(new PPLService(getOSDHttp())); + const para = sampleObservabilityVizParagraph; + para.isSelected = true; + + uiSettingsService.get = jest.fn().mockReturnValue('YYYY-MMM-DD HH:mm:ss'); + const setVisInput = jest.fn(); + const utils = render( + + null} + /> + + ); + expect(utils.container.textContent).toMatch('2020-Jul-21 18:37:44 - 2020-Aug-20 18:37:44'); + expect(utils.container.firstChild).toMatchSnapshot(); + }); + it('renders other types of outputs', () => { const para = sampleParsedParagraghs1[0]; para.isSelected = true; diff --git a/test/sample_default_notebooks.tsx b/test/sample_default_notebooks.tsx index 0356d3a65..09a0c18f1 100644 --- a/test/sample_default_notebooks.tsx +++ b/test/sample_default_notebooks.tsx @@ -168,6 +168,33 @@ export const sampleParsedParagraghs1 = [ }, ]; +export const sampleObservabilityVizParagraph = { + uniqueId: 'paragraph_6d3237a9-6486-4f93-aa25-0a1c838faahh', + isRunning: false, + inQueue: false, + isSelected: false, + isInputHidden: false, + isOutputHidden: false, + showAddPara: false, + isVizualisation: true, + vizObjectInput: + '{"viewMode":"view","panels":{"1":{"gridData":{"x":0,"y":0,"w":50,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"xmcchIwB5xYbk0tldrMA"}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"id2ae6b50-aa91-11ee-b006-2351d419df89","timeRange":{"to":"2024-01-03T23:42:52.909Z","from":"2023-12-04T23:42:52.909Z"},"title":"embed_viz_id2ae6b50-aa91-11ee-b006-2351d419df89","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', + id: 3, + inp: + '{"viewMode":"view","panels":{"1":{"gridData":{"x":0,"y":0,"w":50,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"xmcchIwB5xYbk0tldrMA"}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"id2ae6b50-aa91-11ee-b006-2351d419df89","timeRange":{"to":"2024-01-03T23:42:52.909Z","from":"2023-12-04T23:42:52.909Z"},"title":"embed_viz_id2ae6b50-aa91-11ee-b006-2351d419df89","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', + lang: 'text/x-', + isInputExpanded: false, + isOutputStale: false, + paraDivRef: undefined, + paraRef: undefined, + visEndTime: '2020-08-20T18:37:44.710Z', + visSavedObjId: '935afa20-e0cd-11e7-9d07-1398ccfcefa3', + visStartTime: '2020-07-21T18:37:44.710Z', + editorLanguage: '', + typeOut: ['OBSERVABILITY_VISUALIZATION'], + out: [''], +}; + // Sample notebook with all input and cleared outputs export const sampleNotebook2 = { id: 'note_5f4b9eed-5898-4b39-ba6c-755c0fadd84e', From 9630f531c3d90a1937a1c54dd7c01e627d8f5a92 Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Thu, 4 Jan 2024 16:19:53 -0800 Subject: [PATCH 09/14] remove unnecessary jest mock import Signed-off-by: Shenoy Pratik --- .../paragraph_components/__tests__/para_output.test.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx b/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx index c19ebd2c6..103cf8039 100644 --- a/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx +++ b/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx @@ -3,7 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -jest.mock('../../../../../test/__mocks__/httpClientMock'); import { render } from '@testing-library/react'; import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; From a817e66e72779cf17a060b838fd4d1d875223fd9 Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Thu, 4 Jan 2024 16:42:52 -0800 Subject: [PATCH 10/14] history.push jest function added Signed-off-by: Shenoy Pratik --- .../components/notebooks/components/__tests__/notebook.test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/public/components/notebooks/components/__tests__/notebook.test.tsx b/public/components/notebooks/components/__tests__/notebook.test.tsx index e0462821a..f8f0c209f 100644 --- a/public/components/notebooks/components/__tests__/notebook.test.tsx +++ b/public/components/notebooks/components/__tests__/notebook.test.tsx @@ -56,6 +56,7 @@ describe(' spec', () => { location.search = ''; const history = jest.fn() as any; history.replace = jest.fn(); + history.push = jest.fn(); it('renders the empty component and test reporting action button', async () => { httpClient.get = jest.fn(() => Promise.resolve((emptyNotebook as unknown) as HttpResponse)); From 9867c4422b8f05f8865d49de304d62190162423a Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Mon, 8 Jan 2024 14:22:01 -0800 Subject: [PATCH 11/14] merge notebooks tests contants file Signed-off-by: Shenoy Pratik --- .../components/__tests__/notebook.test.tsx | 3 +- .../helpers/__tests__/default_parser.test.tsx | 13 +- .../__tests__/para_input.test.tsx | 2 +- .../__tests__/para_output.test.tsx | 2 +- .../__tests__/paragraphs.test.tsx | 6 +- test/notebooks_constants.ts | 389 +++++++++++++++++ test/sample_default_notebooks.tsx | 391 ------------------ 7 files changed, 402 insertions(+), 404 deletions(-) delete mode 100644 test/sample_default_notebooks.tsx diff --git a/public/components/notebooks/components/__tests__/notebook.test.tsx b/public/components/notebooks/components/__tests__/notebook.test.tsx index f8f0c209f..266583fce 100644 --- a/public/components/notebooks/components/__tests__/notebook.test.tsx +++ b/public/components/notebooks/components/__tests__/notebook.test.tsx @@ -15,11 +15,12 @@ import { clearOutputNotebook, codeBlockNotebook, codePlaceholderText, + emptyNotebook, notebookPutResponse, runCodeBlockResponse, + sampleNotebook1, } from '../../../../../test/notebooks_constants'; import { sampleSavedVisualization } from '../../../../../test/panels_constants'; -import { emptyNotebook, sampleNotebook1 } from '../../../../../test/sample_default_notebooks'; import PPLService from '../../../../services/requests/ppl'; import { SavedObjectsActions } from '../../../../services/saved_objects/saved_object_client/saved_objects_actions'; import { Notebook } from '../notebook'; diff --git a/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx b/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx index fdcabaa00..c29adf2f9 100644 --- a/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx +++ b/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx @@ -11,19 +11,18 @@ import { sampleNotebook5, sampleParsedParagraghs1, sampleParsedParagraghs2, -} from '../../../../../../test/sample_default_notebooks'; +} from '../../../../../../test/notebooks_constants'; import { defaultParagraphParser } from '../default_parser'; // Perfect schema describe('Testing default backend parser function with perfect schema', () => { - test('defaultParagraphParserTest1', (done) => { + it('defaultParagraphParserTest1', () => { const parsedParagraphs1 = defaultParagraphParser(sampleNotebook1.paragraphs); const parsedParagraphs2 = defaultParagraphParser(sampleNotebook2.paragraphs); const parsedParagraphs3 = defaultParagraphParser([]); expect(parsedParagraphs1).toEqual(sampleParsedParagraghs1); expect(parsedParagraphs2).toEqual(sampleParsedParagraghs2); expect(parsedParagraphs3).toEqual([]); - done(); }); it('returns parsed paragraphs', () => { @@ -82,15 +81,15 @@ describe('Testing default backend parser function with perfect schema', () => { // Issue in schema describe('Testing default backend parser function with wrong schema', () => { - test('defaultParagraphParserTest2', (done) => { + it('defaultParagraphParserTest2', () => { expect(() => { - const parsedParagraphs1 = defaultParagraphParser(sampleNotebook3.paragraphs); + const _parsedParagraphs1 = defaultParagraphParser(sampleNotebook3.paragraphs); }).toThrow(Error); expect(() => { - const parsedParagraphs2 = defaultParagraphParser(sampleNotebook4.paragraphs); + const _parsedParagraphs2 = defaultParagraphParser(sampleNotebook4.paragraphs); }).toThrow(Error); expect(() => { - const parsedParagraphs3 = defaultParagraphParser(sampleNotebook5.paragraphs); + const _parsedParagraphs3 = defaultParagraphParser(sampleNotebook5.paragraphs); }).toThrow(Error); done(); }); diff --git a/public/components/notebooks/components/paragraph_components/__tests__/para_input.test.tsx b/public/components/notebooks/components/paragraph_components/__tests__/para_input.test.tsx index 112326e1e..4841064a0 100644 --- a/public/components/notebooks/components/paragraph_components/__tests__/para_input.test.tsx +++ b/public/components/notebooks/components/paragraph_components/__tests__/para_input.test.tsx @@ -7,7 +7,7 @@ import { fireEvent, render, waitFor } from '@testing-library/react'; import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; -import { sampleParsedParagraghs1 } from '../../../../../../test/sample_default_notebooks'; +import { sampleParsedParagraghs1 } from '../../../../../../test/notebooks_constants'; import { ParaInput } from '../para_input'; describe(' spec', () => { diff --git a/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx b/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx index 103cf8039..a7f35a6a0 100644 --- a/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx +++ b/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx @@ -17,7 +17,7 @@ import { import { sampleObservabilityVizParagraph, sampleParsedParagraghs1, -} from '../../../../../../test/sample_default_notebooks'; +} from '../../../../../../test/notebooks_constants'; import { rootReducer } from '../../../../../framework/redux/reducers'; import PPLService from '../../../../../services/requests/ppl'; import { ParaOutput } from '../para_output'; diff --git a/public/components/notebooks/components/paragraph_components/__tests__/paragraphs.test.tsx b/public/components/notebooks/components/paragraph_components/__tests__/paragraphs.test.tsx index 381463f88..f2b054ff3 100644 --- a/public/components/notebooks/components/paragraph_components/__tests__/paragraphs.test.tsx +++ b/public/components/notebooks/components/paragraph_components/__tests__/paragraphs.test.tsx @@ -7,8 +7,8 @@ import { render } from '@testing-library/react'; import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; -import httpClientMock from '../../../../../../test/__mocks__/httpClientMock'; -import { sampleParsedParagraghs1 } from '../../../../../../test/sample_default_notebooks'; +import { getOSDHttp } from '../../../../../../common/utils'; +import { sampleParsedParagraghs1 } from '../../../../../../test/notebooks_constants'; import { Paragraphs } from '../paragraphs'; jest.mock('../../../../../../../../src/plugins/embeddable/public', () => ({ @@ -50,7 +50,7 @@ describe(' spec', () => { addPara={addPara} DashboardContainerByValueRenderer={DashboardContainerByValueRenderer} deleteVizualization={deleteVizualization} - http={httpClientMock} + http={getOSDHttp()} selectedViewId="view_both" setSelectedViewId={setSelectedViewId} deletePara={deletePara} diff --git a/test/notebooks_constants.ts b/test/notebooks_constants.ts index 6075a8107..a936b41ac 100644 --- a/test/notebooks_constants.ts +++ b/test/notebooks_constants.ts @@ -52,3 +52,392 @@ export const notebookPutResponse = { status: 'OK', message: { objectId: '69CpaYwBKIZhlDIhx-OK' }, }; + +// ///////////////// /////////////////// /////////////////// SAMPLE NOTEBOOKS DEFAULTS /////////////////// /////////////////// /////////////////// + +export const emptyNotebook = { + path: 'sample-notebook-1', + dateCreated: '2023-12-14T18:49:43.375Z', + dateModified: '2023-12-15T06:13:23.463Z', + paragraphs: [], +}; + +// Sample notebook with all input and output +export const sampleNotebook1 = { + id: 'note_5f4b9eed-5898-4b39-ba6c-755c0fadd84e', + dateCreated: '2020-08-20T18:00:59.845Z', + name: 'test 1', + dateModified: '2020-08-20T18:37:56.844Z', + pluginVersion: '7.9.0', + backend: 'Default', + paragraphs: [ + { + output: [{ result: '# Type your input here', outputType: 'MARKDOWN', execution_time: '0s' }], + input: { inputText: '# Type your input here', inputType: 'MARKDOWN' }, + dateCreated: '2020-08-20T18:00:59.845Z', + dateModified: '2020-08-20T18:00:59.845Z', + id: 'paragraph_1a710988-ec19-4caa-83cc-38eb609427d1', + }, + { + output: [{ result: '# add code here\n', outputType: 'MARKDOWN', execution_time: '0s' }], + input: { inputText: '# add code here\n', inputType: 'MARKDOWN' }, + dateCreated: '2020-08-20T18:01:07.662Z', + dateModified: '2020-08-20T18:01:18.295Z', + id: 'paragraph_c3107b15-da7d-4836-aef4-0996abbc8ab2', + }, + { + output: [{ result: '', outputType: 'VISUALIZATION', execution_time: '0s' }], + input: { + inputText: + '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', + inputType: 'VISUALIZATION', + }, + dateCreated: '2020-08-20T18:37:44.809Z', + dateModified: '2020-08-20T18:37:56.844Z', + id: 'paragraph_6d3237a9-6486-4f93-aa25-0a1c838faabd', + }, + { + output: [ + { + result: + '{"schema":[{"name":"FlightNum","type":"keyword"},{"name":"Origin","type":"keyword"},{"name":"OriginLocation","type":"geo_point"},{"name":"DestLocation","type":"geo_point"},{"name":"FlightDelay","type":"boolean"},{"name":"DistanceMiles","type":"float"},{"name":"FlightTimeMin","type":"float"},{"name":"OriginWeather","type":"keyword"},{"name":"dayOfWeek","type":"integer"},{"name":"AvgTicketPrice","type":"float"},{"name":"Carrier","type":"keyword"},{"name":"FlightDelayMin","type":"integer"},{"name":"OriginRegion","type":"keyword"},{"name":"DestAirportID","type":"keyword"},{"name":"FlightDelayType","type":"keyword"},{"name":"timestamp","type":"timestamp"},{"name":"Dest","type":"keyword"},{"name":"FlightTimeHour","type":"keyword"},{"name":"Cancelled","type":"boolean"},{"name":"DistanceKilometers","type":"float"},{"name":"OriginCityName","type":"keyword"},{"name":"DestWeather","type":"keyword"},{"name":"OriginCountry","type":"keyword"},{"name":"DestCountry","type":"keyword"},{"name":"DestRegion","type":"keyword"},{"name":"DestCityName","type":"keyword"},{"name":"OriginAirportID","type":"keyword"}],"datarows":[["9HY9SWR","Frankfurt am Main Airport",{"lat":50.033333,"lon":8.570556},{"lat":-33.94609833,"lon":151.177002},false,10247.856,1030.7704,"Sunny",0,841.2656,"OpenSearch Dashboards Airlines",0,"DE-HE","SYD","No Delay","2021-11-01 00:00:00","Sydney Kingsford Smith International Airport","17.179506930998397",false,16492.326,"Frankfurt am Main","Rain","DE","AU","SE-BD","Sydney","FRA"],["X98CCZO","Cape Town International Airport",{"lat":-33.96480179,"lon":18.60169983},{"lat":45.505299,"lon":12.3519},false,5482.6064,464.3895,"Clear",0,882.98267,"Logstash Airways",0,"SE-BD","VE05","No Delay","2021-11-01 18:27:00","Venice Marco Polo Airport","7.73982468459836",false,8823.4,"Cape Town","Sunny","ZA","IT","IT-34","Venice","CPT"]],"total":2,"size":2,"status":200}', + outputType: 'QUERY', + execution_time: '0s', + }, + ], + input: { + inputText: '%sql select * from opensearch_dashboards_sample_data_flights limit 2', + inputType: 'QUERY', + }, + dateCreated: '2020-08-20T18:37:44.809Z', + dateModified: '2020-08-20T18:37:56.844Z', + id: 'paragraph_f1b2db55-8704-4822-a8ff-6445fe1fa10c', + }, + ], +}; + +// Parsed Output of sample notebook1 +export const sampleParsedParagraghs1 = [ + { + uniqueId: 'paragraph_1a710988-ec19-4caa-83cc-38eb609427d1', + isRunning: false, + inQueue: false, + isSelected: false, + isInputHidden: false, + isOutputHidden: false, + showAddPara: false, + isVizualisation: false, + vizObjectInput: '', + id: 1, + inp: '# Type your input here', + isInputExpanded: false, + isOutputStale: false, + paraDivRef: undefined, + paraRef: undefined, + visEndTime: undefined, + visSavedObjId: undefined, + visStartTime: undefined, + lang: 'text/x-md', + editorLanguage: 'md', + typeOut: ['MARKDOWN'], + out: ['# Type your input here'], + }, + { + uniqueId: 'paragraph_c3107b15-da7d-4836-aef4-0996abbc8ab2', + isRunning: false, + inQueue: false, + isSelected: false, + isInputHidden: false, + isOutputHidden: false, + showAddPara: false, + isVizualisation: false, + vizObjectInput: '', + id: 2, + inp: '# add code here\n', + isInputExpanded: false, + isOutputStale: false, + paraDivRef: undefined, + paraRef: undefined, + visEndTime: undefined, + visSavedObjId: undefined, + visStartTime: undefined, + lang: 'text/x-md', + editorLanguage: 'md', + typeOut: ['MARKDOWN'], + out: ['# add code here\n'], + }, + { + uniqueId: 'paragraph_6d3237a9-6486-4f93-aa25-0a1c838faabd', + isRunning: false, + inQueue: false, + isSelected: false, + isInputHidden: false, + isOutputHidden: false, + showAddPara: false, + isVizualisation: true, + vizObjectInput: + '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', + id: 3, + inp: + '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', + lang: 'text/x-', + isInputExpanded: false, + isOutputStale: false, + paraDivRef: undefined, + paraRef: undefined, + visEndTime: '2020-08-20T18:37:44.710Z', + visSavedObjId: '935afa20-e0cd-11e7-9d07-1398ccfcefa3', + visStartTime: '2020-07-21T18:37:44.710Z', + editorLanguage: '', + typeOut: ['VISUALIZATION'], + out: [''], + }, + { + uniqueId: 'paragraph_f1b2db55-8704-4822-a8ff-6445fe1fa10c', + isRunning: false, + inQueue: false, + isSelected: false, + isInputHidden: false, + isOutputHidden: false, + showAddPara: false, + isVizualisation: false, + vizObjectInput: '', + id: 4, + inp: `%sql select * from opensearch_dashboards_sample_data_flights limit 2`, + isInputExpanded: false, + isOutputStale: false, + paraDivRef: undefined, + paraRef: undefined, + visEndTime: undefined, + visSavedObjId: undefined, + visStartTime: undefined, + lang: 'text/x-', + editorLanguage: '', + typeOut: ['QUERY'], + out: [ + '{"schema":[{"name":"FlightNum","type":"keyword"},{"name":"Origin","type":"keyword"},{"name":"OriginLocation","type":"geo_point"},{"name":"DestLocation","type":"geo_point"},{"name":"FlightDelay","type":"boolean"},{"name":"DistanceMiles","type":"float"},{"name":"FlightTimeMin","type":"float"},{"name":"OriginWeather","type":"keyword"},{"name":"dayOfWeek","type":"integer"},{"name":"AvgTicketPrice","type":"float"},{"name":"Carrier","type":"keyword"},{"name":"FlightDelayMin","type":"integer"},{"name":"OriginRegion","type":"keyword"},{"name":"DestAirportID","type":"keyword"},{"name":"FlightDelayType","type":"keyword"},{"name":"timestamp","type":"timestamp"},{"name":"Dest","type":"keyword"},{"name":"FlightTimeHour","type":"keyword"},{"name":"Cancelled","type":"boolean"},{"name":"DistanceKilometers","type":"float"},{"name":"OriginCityName","type":"keyword"},{"name":"DestWeather","type":"keyword"},{"name":"OriginCountry","type":"keyword"},{"name":"DestCountry","type":"keyword"},{"name":"DestRegion","type":"keyword"},{"name":"DestCityName","type":"keyword"},{"name":"OriginAirportID","type":"keyword"}],"datarows":[["9HY9SWR","Frankfurt am Main Airport",{"lat":50.033333,"lon":8.570556},{"lat":-33.94609833,"lon":151.177002},false,10247.856,1030.7704,"Sunny",0,841.2656,"OpenSearch Dashboards Airlines",0,"DE-HE","SYD","No Delay","2021-11-01 00:00:00","Sydney Kingsford Smith International Airport","17.179506930998397",false,16492.326,"Frankfurt am Main","Rain","DE","AU","SE-BD","Sydney","FRA"],["X98CCZO","Cape Town International Airport",{"lat":-33.96480179,"lon":18.60169983},{"lat":45.505299,"lon":12.3519},false,5482.6064,464.3895,"Clear",0,882.98267,"Logstash Airways",0,"SE-BD","VE05","No Delay","2021-11-01 18:27:00","Venice Marco Polo Airport","7.73982468459836",false,8823.4,"Cape Town","Sunny","ZA","IT","IT-34","Venice","CPT"]],"total":2,"size":2,"status":200}', + ], + }, +]; + +export const sampleObservabilityVizParagraph = { + uniqueId: 'paragraph_6d3237a9-6486-4f93-aa25-0a1c838faahh', + isRunning: false, + inQueue: false, + isSelected: false, + isInputHidden: false, + isOutputHidden: false, + showAddPara: false, + isVizualisation: true, + vizObjectInput: + '{"viewMode":"view","panels":{"1":{"gridData":{"x":0,"y":0,"w":50,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"xmcchIwB5xYbk0tldrMA"}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"id2ae6b50-aa91-11ee-b006-2351d419df89","timeRange":{"to":"2024-01-03T23:42:52.909Z","from":"2023-12-04T23:42:52.909Z"},"title":"embed_viz_id2ae6b50-aa91-11ee-b006-2351d419df89","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', + id: 3, + inp: + '{"viewMode":"view","panels":{"1":{"gridData":{"x":0,"y":0,"w":50,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"xmcchIwB5xYbk0tldrMA"}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"id2ae6b50-aa91-11ee-b006-2351d419df89","timeRange":{"to":"2024-01-03T23:42:52.909Z","from":"2023-12-04T23:42:52.909Z"},"title":"embed_viz_id2ae6b50-aa91-11ee-b006-2351d419df89","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', + lang: 'text/x-', + isInputExpanded: false, + isOutputStale: false, + paraDivRef: undefined, + paraRef: undefined, + visEndTime: '2020-08-20T18:37:44.710Z', + visSavedObjId: '935afa20-e0cd-11e7-9d07-1398ccfcefa3', + visStartTime: '2020-07-21T18:37:44.710Z', + editorLanguage: '', + typeOut: ['OBSERVABILITY_VISUALIZATION'], + out: [''], +}; + +// Sample notebook with all input and cleared outputs +export const sampleNotebook2 = { + id: 'note_5f4b9eed-5898-4b39-ba6c-755c0fadd84e', + dateCreated: '2020-08-20T18:00:59.845Z', + name: 'test 1', + dateModified: '2020-08-20T19:13:06.509Z', + pluginVersion: '7.9.0', + backend: 'Default', + paragraphs: [ + { + output: [ + { + result: + '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__', + outputType: 'MARKDOWN', + execution_time: '0s', + }, + ], + input: { + inputText: + '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__', + inputType: 'MARKDOWN', + }, + dateCreated: '2020-08-20T18:00:59.845Z', + dateModified: '2020-08-20T19:13:06.509Z', + id: 'paragraph_1a710988-ec19-4caa-83cc-38eb609427d1', + }, + { + output: [], + input: { inputText: '# no output here\n', inputType: 'MARKDOWN' }, + dateCreated: '2020-08-20T18:01:07.662Z', + dateModified: '2020-08-20T19:09:19.210Z', + id: 'paragraph_c3107b15-da7d-4836-aef4-0996abbc8ab2', + }, + { + output: [], + input: { + inputText: + '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', + inputType: 'VISUALIZATION', + }, + dateCreated: '2020-08-20T18:37:44.809Z', + dateModified: '2020-08-20T18:37:56.844Z', + id: 'paragraph_6d3237a9-6486-4f93-aa25-0a1c838faabd', + }, + ], +}; + +// Parsed Output of sample notebook2 +export const sampleParsedParagraghs2 = [ + { + uniqueId: 'paragraph_1a710988-ec19-4caa-83cc-38eb609427d1', + isRunning: false, + inQueue: false, + isSelected: false, + isInputHidden: false, + isOutputHidden: false, + showAddPara: false, + isVizualisation: false, + vizObjectInput: '', + id: 1, + inp: + '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__', + lang: 'text/x-md', + isInputExpanded: false, + isOutputStale: false, + paraDivRef: undefined, + paraRef: undefined, + visEndTime: undefined, + visSavedObjId: undefined, + visStartTime: undefined, + editorLanguage: 'md', + typeOut: ['MARKDOWN'], + out: [ + '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__', + ], + }, + { + uniqueId: 'paragraph_c3107b15-da7d-4836-aef4-0996abbc8ab2', + isRunning: false, + inQueue: false, + isSelected: false, + isInputHidden: false, + isOutputHidden: false, + showAddPara: false, + isVizualisation: false, + vizObjectInput: '', + id: 2, + inp: '# no output here\n', + isInputExpanded: false, + isOutputStale: false, + paraDivRef: undefined, + paraRef: undefined, + visEndTime: undefined, + visSavedObjId: undefined, + visStartTime: undefined, + lang: 'text/x-md', + editorLanguage: 'md', + typeOut: [], + out: [], + }, + { + uniqueId: 'paragraph_6d3237a9-6486-4f93-aa25-0a1c838faabd', + isRunning: false, + inQueue: false, + isSelected: false, + isInputHidden: false, + isOutputHidden: false, + showAddPara: false, + isVizualisation: true, + vizObjectInput: + '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', + id: 3, + inp: + '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', + lang: 'text/x-', + isInputExpanded: false, + isOutputStale: false, + paraDivRef: undefined, + paraRef: undefined, + visEndTime: '2020-08-20T18:37:44.710Z', + visSavedObjId: '935afa20-e0cd-11e7-9d07-1398ccfcefa3', + visStartTime: '2020-07-21T18:37:44.710Z', + editorLanguage: '', + typeOut: [], + out: [], + }, +]; + +// Sample notebook with no input +export const sampleNotebook3 = { + id: 'note_5f4b9eed-5898-4b39-ba6c-755c0fadd84e', + dateCreated: '2020-08-20T18:00:59.845Z', + name: 'test 1', + dateModified: '2020-08-20T19:13:06.509Z', + pluginVersion: '7.9.0', + backend: 'Default', + paragraphs: [ + { + output: [ + { + result: + '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__', + outputType: 'MARKDOWN', + execution_time: '0s', + }, + ], + dateCreated: '2020-08-20T18:00:59.845Z', + dateModified: '2020-08-20T19:13:06.509Z', + id: 'paragraph_1a710988-ec19-4caa-83cc-38eb609427d1', + }, + ], +}; + +// Sample notebook with no paragraph id +export const sampleNotebook4 = { + id: 'note_5f4b9eed-5898-4b39-ba6c-755c0fadd84e', + dateCreated: '2020-08-20T18:00:59.845Z', + name: 'test 1', + dateModified: '2020-08-20T19:13:06.509Z', + pluginVersion: '7.9.0', + backend: 'Default', + paragraphs: [ + { + output: [ + { + result: + '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__', + outputType: 'MARKDOWN', + execution_time: '0s', + }, + ], + dateCreated: '2020-08-20T18:00:59.845Z', + dateModified: '2020-08-20T19:13:06.509Z', + }, + ], +}; + +// Sample notebook with no input and output +export const sampleNotebook5 = { + id: 'note_5f4b9eed-5898-4b39-ba6c-755c0fadd84e', + dateCreated: '2020-08-20T18:00:59.845Z', + name: 'test 1', + dateModified: '2020-08-20T19:13:06.509Z', + pluginVersion: '7.9.0', + backend: 'Default', + paragraphs: [ + { + dateCreated: '2020-08-20T18:00:59.845Z', + dateModified: '2020-08-20T19:13:06.509Z', + id: 'paragraph_c3107b15-da7d-4836-aef4-0996abbc8ab2', + }, + ], +}; diff --git a/test/sample_default_notebooks.tsx b/test/sample_default_notebooks.tsx deleted file mode 100644 index 09a0c18f1..000000000 --- a/test/sample_default_notebooks.tsx +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export const emptyNotebook = { - path: 'sample-notebook-1', - dateCreated: '2023-12-14T18:49:43.375Z', - dateModified: '2023-12-15T06:13:23.463Z', - paragraphs: [], -}; - -// Sample notebook with all input and output -export const sampleNotebook1 = { - id: 'note_5f4b9eed-5898-4b39-ba6c-755c0fadd84e', - dateCreated: '2020-08-20T18:00:59.845Z', - name: 'test 1', - dateModified: '2020-08-20T18:37:56.844Z', - pluginVersion: '7.9.0', - backend: 'Default', - paragraphs: [ - { - output: [{ result: '# Type your input here', outputType: 'MARKDOWN', execution_time: '0s' }], - input: { inputText: '# Type your input here', inputType: 'MARKDOWN' }, - dateCreated: '2020-08-20T18:00:59.845Z', - dateModified: '2020-08-20T18:00:59.845Z', - id: 'paragraph_1a710988-ec19-4caa-83cc-38eb609427d1', - }, - { - output: [{ result: '# add code here\n', outputType: 'MARKDOWN', execution_time: '0s' }], - input: { inputText: '# add code here\n', inputType: 'MARKDOWN' }, - dateCreated: '2020-08-20T18:01:07.662Z', - dateModified: '2020-08-20T18:01:18.295Z', - id: 'paragraph_c3107b15-da7d-4836-aef4-0996abbc8ab2', - }, - { - output: [{ result: '', outputType: 'VISUALIZATION', execution_time: '0s' }], - input: { - inputText: - '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', - inputType: 'VISUALIZATION', - }, - dateCreated: '2020-08-20T18:37:44.809Z', - dateModified: '2020-08-20T18:37:56.844Z', - id: 'paragraph_6d3237a9-6486-4f93-aa25-0a1c838faabd', - }, - { - output: [ - { - result: - '{"schema":[{"name":"FlightNum","type":"keyword"},{"name":"Origin","type":"keyword"},{"name":"OriginLocation","type":"geo_point"},{"name":"DestLocation","type":"geo_point"},{"name":"FlightDelay","type":"boolean"},{"name":"DistanceMiles","type":"float"},{"name":"FlightTimeMin","type":"float"},{"name":"OriginWeather","type":"keyword"},{"name":"dayOfWeek","type":"integer"},{"name":"AvgTicketPrice","type":"float"},{"name":"Carrier","type":"keyword"},{"name":"FlightDelayMin","type":"integer"},{"name":"OriginRegion","type":"keyword"},{"name":"DestAirportID","type":"keyword"},{"name":"FlightDelayType","type":"keyword"},{"name":"timestamp","type":"timestamp"},{"name":"Dest","type":"keyword"},{"name":"FlightTimeHour","type":"keyword"},{"name":"Cancelled","type":"boolean"},{"name":"DistanceKilometers","type":"float"},{"name":"OriginCityName","type":"keyword"},{"name":"DestWeather","type":"keyword"},{"name":"OriginCountry","type":"keyword"},{"name":"DestCountry","type":"keyword"},{"name":"DestRegion","type":"keyword"},{"name":"DestCityName","type":"keyword"},{"name":"OriginAirportID","type":"keyword"}],"datarows":[["9HY9SWR","Frankfurt am Main Airport",{"lat":50.033333,"lon":8.570556},{"lat":-33.94609833,"lon":151.177002},false,10247.856,1030.7704,"Sunny",0,841.2656,"OpenSearch Dashboards Airlines",0,"DE-HE","SYD","No Delay","2021-11-01 00:00:00","Sydney Kingsford Smith International Airport","17.179506930998397",false,16492.326,"Frankfurt am Main","Rain","DE","AU","SE-BD","Sydney","FRA"],["X98CCZO","Cape Town International Airport",{"lat":-33.96480179,"lon":18.60169983},{"lat":45.505299,"lon":12.3519},false,5482.6064,464.3895,"Clear",0,882.98267,"Logstash Airways",0,"SE-BD","VE05","No Delay","2021-11-01 18:27:00","Venice Marco Polo Airport","7.73982468459836",false,8823.4,"Cape Town","Sunny","ZA","IT","IT-34","Venice","CPT"]],"total":2,"size":2,"status":200}', - outputType: 'QUERY', - execution_time: '0s', - }, - ], - input: { - inputText: '%sql select * from opensearch_dashboards_sample_data_flights limit 2', - inputType: 'QUERY', - }, - dateCreated: '2020-08-20T18:37:44.809Z', - dateModified: '2020-08-20T18:37:56.844Z', - id: 'paragraph_f1b2db55-8704-4822-a8ff-6445fe1fa10c', - }, - ], -}; - -// Parsed Output of sample notebook1 -export const sampleParsedParagraghs1 = [ - { - uniqueId: 'paragraph_1a710988-ec19-4caa-83cc-38eb609427d1', - isRunning: false, - inQueue: false, - isSelected: false, - isInputHidden: false, - isOutputHidden: false, - showAddPara: false, - isVizualisation: false, - vizObjectInput: '', - id: 1, - inp: '# Type your input here', - isInputExpanded: false, - isOutputStale: false, - paraDivRef: undefined, - paraRef: undefined, - visEndTime: undefined, - visSavedObjId: undefined, - visStartTime: undefined, - lang: 'text/x-md', - editorLanguage: 'md', - typeOut: ['MARKDOWN'], - out: ['# Type your input here'], - }, - { - uniqueId: 'paragraph_c3107b15-da7d-4836-aef4-0996abbc8ab2', - isRunning: false, - inQueue: false, - isSelected: false, - isInputHidden: false, - isOutputHidden: false, - showAddPara: false, - isVizualisation: false, - vizObjectInput: '', - id: 2, - inp: '# add code here\n', - isInputExpanded: false, - isOutputStale: false, - paraDivRef: undefined, - paraRef: undefined, - visEndTime: undefined, - visSavedObjId: undefined, - visStartTime: undefined, - lang: 'text/x-md', - editorLanguage: 'md', - typeOut: ['MARKDOWN'], - out: ['# add code here\n'], - }, - { - uniqueId: 'paragraph_6d3237a9-6486-4f93-aa25-0a1c838faabd', - isRunning: false, - inQueue: false, - isSelected: false, - isInputHidden: false, - isOutputHidden: false, - showAddPara: false, - isVizualisation: true, - vizObjectInput: - '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', - id: 3, - inp: - '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', - lang: 'text/x-', - isInputExpanded: false, - isOutputStale: false, - paraDivRef: undefined, - paraRef: undefined, - visEndTime: '2020-08-20T18:37:44.710Z', - visSavedObjId: '935afa20-e0cd-11e7-9d07-1398ccfcefa3', - visStartTime: '2020-07-21T18:37:44.710Z', - editorLanguage: '', - typeOut: ['VISUALIZATION'], - out: [''], - }, - { - uniqueId: 'paragraph_f1b2db55-8704-4822-a8ff-6445fe1fa10c', - isRunning: false, - inQueue: false, - isSelected: false, - isInputHidden: false, - isOutputHidden: false, - showAddPara: false, - isVizualisation: false, - vizObjectInput: '', - id: 4, - inp: `%sql select * from opensearch_dashboards_sample_data_flights limit 2`, - isInputExpanded: false, - isOutputStale: false, - paraDivRef: undefined, - paraRef: undefined, - visEndTime: undefined, - visSavedObjId: undefined, - visStartTime: undefined, - lang: 'text/x-', - editorLanguage: '', - typeOut: ['QUERY'], - out: [ - '{"schema":[{"name":"FlightNum","type":"keyword"},{"name":"Origin","type":"keyword"},{"name":"OriginLocation","type":"geo_point"},{"name":"DestLocation","type":"geo_point"},{"name":"FlightDelay","type":"boolean"},{"name":"DistanceMiles","type":"float"},{"name":"FlightTimeMin","type":"float"},{"name":"OriginWeather","type":"keyword"},{"name":"dayOfWeek","type":"integer"},{"name":"AvgTicketPrice","type":"float"},{"name":"Carrier","type":"keyword"},{"name":"FlightDelayMin","type":"integer"},{"name":"OriginRegion","type":"keyword"},{"name":"DestAirportID","type":"keyword"},{"name":"FlightDelayType","type":"keyword"},{"name":"timestamp","type":"timestamp"},{"name":"Dest","type":"keyword"},{"name":"FlightTimeHour","type":"keyword"},{"name":"Cancelled","type":"boolean"},{"name":"DistanceKilometers","type":"float"},{"name":"OriginCityName","type":"keyword"},{"name":"DestWeather","type":"keyword"},{"name":"OriginCountry","type":"keyword"},{"name":"DestCountry","type":"keyword"},{"name":"DestRegion","type":"keyword"},{"name":"DestCityName","type":"keyword"},{"name":"OriginAirportID","type":"keyword"}],"datarows":[["9HY9SWR","Frankfurt am Main Airport",{"lat":50.033333,"lon":8.570556},{"lat":-33.94609833,"lon":151.177002},false,10247.856,1030.7704,"Sunny",0,841.2656,"OpenSearch Dashboards Airlines",0,"DE-HE","SYD","No Delay","2021-11-01 00:00:00","Sydney Kingsford Smith International Airport","17.179506930998397",false,16492.326,"Frankfurt am Main","Rain","DE","AU","SE-BD","Sydney","FRA"],["X98CCZO","Cape Town International Airport",{"lat":-33.96480179,"lon":18.60169983},{"lat":45.505299,"lon":12.3519},false,5482.6064,464.3895,"Clear",0,882.98267,"Logstash Airways",0,"SE-BD","VE05","No Delay","2021-11-01 18:27:00","Venice Marco Polo Airport","7.73982468459836",false,8823.4,"Cape Town","Sunny","ZA","IT","IT-34","Venice","CPT"]],"total":2,"size":2,"status":200}', - ], - }, -]; - -export const sampleObservabilityVizParagraph = { - uniqueId: 'paragraph_6d3237a9-6486-4f93-aa25-0a1c838faahh', - isRunning: false, - inQueue: false, - isSelected: false, - isInputHidden: false, - isOutputHidden: false, - showAddPara: false, - isVizualisation: true, - vizObjectInput: - '{"viewMode":"view","panels":{"1":{"gridData":{"x":0,"y":0,"w":50,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"xmcchIwB5xYbk0tldrMA"}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"id2ae6b50-aa91-11ee-b006-2351d419df89","timeRange":{"to":"2024-01-03T23:42:52.909Z","from":"2023-12-04T23:42:52.909Z"},"title":"embed_viz_id2ae6b50-aa91-11ee-b006-2351d419df89","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', - id: 3, - inp: - '{"viewMode":"view","panels":{"1":{"gridData":{"x":0,"y":0,"w":50,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"xmcchIwB5xYbk0tldrMA"}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"id2ae6b50-aa91-11ee-b006-2351d419df89","timeRange":{"to":"2024-01-03T23:42:52.909Z","from":"2023-12-04T23:42:52.909Z"},"title":"embed_viz_id2ae6b50-aa91-11ee-b006-2351d419df89","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', - lang: 'text/x-', - isInputExpanded: false, - isOutputStale: false, - paraDivRef: undefined, - paraRef: undefined, - visEndTime: '2020-08-20T18:37:44.710Z', - visSavedObjId: '935afa20-e0cd-11e7-9d07-1398ccfcefa3', - visStartTime: '2020-07-21T18:37:44.710Z', - editorLanguage: '', - typeOut: ['OBSERVABILITY_VISUALIZATION'], - out: [''], -}; - -// Sample notebook with all input and cleared outputs -export const sampleNotebook2 = { - id: 'note_5f4b9eed-5898-4b39-ba6c-755c0fadd84e', - dateCreated: '2020-08-20T18:00:59.845Z', - name: 'test 1', - dateModified: '2020-08-20T19:13:06.509Z', - pluginVersion: '7.9.0', - backend: 'Default', - paragraphs: [ - { - output: [ - { - result: - '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__', - outputType: 'MARKDOWN', - execution_time: '0s', - }, - ], - input: { - inputText: - '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__', - inputType: 'MARKDOWN', - }, - dateCreated: '2020-08-20T18:00:59.845Z', - dateModified: '2020-08-20T19:13:06.509Z', - id: 'paragraph_1a710988-ec19-4caa-83cc-38eb609427d1', - }, - { - output: [], - input: { inputText: '# no output here\n', inputType: 'MARKDOWN' }, - dateCreated: '2020-08-20T18:01:07.662Z', - dateModified: '2020-08-20T19:09:19.210Z', - id: 'paragraph_c3107b15-da7d-4836-aef4-0996abbc8ab2', - }, - { - output: [], - input: { - inputText: - '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', - inputType: 'VISUALIZATION', - }, - dateCreated: '2020-08-20T18:37:44.809Z', - dateModified: '2020-08-20T18:37:56.844Z', - id: 'paragraph_6d3237a9-6486-4f93-aa25-0a1c838faabd', - }, - ], -}; - -// Parsed Output of sample notebook2 -export const sampleParsedParagraghs2 = [ - { - uniqueId: 'paragraph_1a710988-ec19-4caa-83cc-38eb609427d1', - isRunning: false, - inQueue: false, - isSelected: false, - isInputHidden: false, - isOutputHidden: false, - showAddPara: false, - isVizualisation: false, - vizObjectInput: '', - id: 1, - inp: - '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__', - lang: 'text/x-md', - isInputExpanded: false, - isOutputStale: false, - paraDivRef: undefined, - paraRef: undefined, - visEndTime: undefined, - visSavedObjId: undefined, - visStartTime: undefined, - editorLanguage: 'md', - typeOut: ['MARKDOWN'], - out: [ - '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__', - ], - }, - { - uniqueId: 'paragraph_c3107b15-da7d-4836-aef4-0996abbc8ab2', - isRunning: false, - inQueue: false, - isSelected: false, - isInputHidden: false, - isOutputHidden: false, - showAddPara: false, - isVizualisation: false, - vizObjectInput: '', - id: 2, - inp: '# no output here\n', - isInputExpanded: false, - isOutputStale: false, - paraDivRef: undefined, - paraRef: undefined, - visEndTime: undefined, - visSavedObjId: undefined, - visStartTime: undefined, - lang: 'text/x-md', - editorLanguage: 'md', - typeOut: [], - out: [], - }, - { - uniqueId: 'paragraph_6d3237a9-6486-4f93-aa25-0a1c838faabd', - isRunning: false, - inQueue: false, - isSelected: false, - isInputHidden: false, - isOutputHidden: false, - showAddPara: false, - isVizualisation: true, - vizObjectInput: - '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', - id: 3, - inp: - '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}', - lang: 'text/x-', - isInputExpanded: false, - isOutputStale: false, - paraDivRef: undefined, - paraRef: undefined, - visEndTime: '2020-08-20T18:37:44.710Z', - visSavedObjId: '935afa20-e0cd-11e7-9d07-1398ccfcefa3', - visStartTime: '2020-07-21T18:37:44.710Z', - editorLanguage: '', - typeOut: [], - out: [], - }, -]; - -// Sample notebook with no input -export const sampleNotebook3 = { - id: 'note_5f4b9eed-5898-4b39-ba6c-755c0fadd84e', - dateCreated: '2020-08-20T18:00:59.845Z', - name: 'test 1', - dateModified: '2020-08-20T19:13:06.509Z', - pluginVersion: '7.9.0', - backend: 'Default', - paragraphs: [ - { - output: [ - { - result: - '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__', - outputType: 'MARKDOWN', - execution_time: '0s', - }, - ], - dateCreated: '2020-08-20T18:00:59.845Z', - dateModified: '2020-08-20T19:13:06.509Z', - id: 'paragraph_1a710988-ec19-4caa-83cc-38eb609427d1', - }, - ], -}; - -// Sample notebook with no paragraph id -export const sampleNotebook4 = { - id: 'note_5f4b9eed-5898-4b39-ba6c-755c0fadd84e', - dateCreated: '2020-08-20T18:00:59.845Z', - name: 'test 1', - dateModified: '2020-08-20T19:13:06.509Z', - pluginVersion: '7.9.0', - backend: 'Default', - paragraphs: [ - { - output: [ - { - result: - '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__', - outputType: 'MARKDOWN', - execution_time: '0s', - }, - ], - dateCreated: '2020-08-20T18:00:59.845Z', - dateModified: '2020-08-20T19:13:06.509Z', - }, - ], -}; - -// Sample notebook with no input and output -export const sampleNotebook5 = { - id: 'note_5f4b9eed-5898-4b39-ba6c-755c0fadd84e', - dateCreated: '2020-08-20T18:00:59.845Z', - name: 'test 1', - dateModified: '2020-08-20T19:13:06.509Z', - pluginVersion: '7.9.0', - backend: 'Default', - paragraphs: [ - { - dateCreated: '2020-08-20T18:00:59.845Z', - dateModified: '2020-08-20T19:13:06.509Z', - id: 'paragraph_c3107b15-da7d-4836-aef4-0996abbc8ab2', - }, - ], -}; From 4d55ce405eaaa5729f54ca824c92d8aec2de185b Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Mon, 8 Jan 2024 14:31:51 -0800 Subject: [PATCH 12/14] make tests more atomic Signed-off-by: Shenoy Pratik --- .../components/__tests__/notebook.test.tsx | 106 +++++++++++++++++- .../helpers/__tests__/default_parser.test.tsx | 1 - 2 files changed, 101 insertions(+), 6 deletions(-) diff --git a/public/components/notebooks/components/__tests__/notebook.test.tsx b/public/components/notebooks/components/__tests__/notebook.test.tsx index 266583fce..999d74ff9 100644 --- a/public/components/notebooks/components/__tests__/notebook.test.tsx +++ b/public/components/notebooks/components/__tests__/notebook.test.tsx @@ -59,7 +59,31 @@ describe(' spec', () => { history.replace = jest.fn(); history.push = jest.fn(); - it('renders the empty component and test reporting action button', async () => { + it('Renders the empty component', async () => { + httpClient.get = jest.fn(() => Promise.resolve((emptyNotebook as unknown) as HttpResponse)); + const utils = render( + + ); + await waitFor(() => { + expect(utils.getByText('sample-notebook-1')).toBeInTheDocument(); + }); + expect(utils.container.firstChild).toMatchSnapshot(); + }); + + it('test reporting action button', async () => { httpClient.get = jest.fn(() => Promise.resolve((emptyNotebook as unknown) as HttpResponse)); const utils = render( spec', () => { }); }); - it('renders the empty component and checks code block operations', async () => { + it('Checks code block operations', async () => { httpClient.get = jest.fn(() => Promise.resolve((emptyNotebook as unknown) as HttpResponse)); let postFlag = 1; httpClient.post = jest.fn(() => { @@ -176,7 +200,7 @@ describe(' spec', () => { }); }); - it('renders a notebook and checks paragraph actions', async () => { + it('Renders a notebook and checks paragraph actions', async () => { httpClient.get = jest.fn(() => Promise.resolve((codeBlockNotebook as unknown) as HttpResponse)); httpClient.put = jest.fn(() => Promise.resolve((clearOutputNotebook as unknown) as HttpResponse) @@ -254,7 +278,7 @@ describe(' spec', () => { }); }); - it('renders a notebook and checks notebook actions', async () => { + it('Checks notebook rename action', async () => { const renameNotebookMock = jest.fn(() => Promise.resolve((notebookPutResponse as unknown) as HttpResponse) ); @@ -311,6 +335,42 @@ describe(' spec', () => { await waitFor(() => { expect(renameNotebookMock).toHaveBeenCalledTimes(1); }); + }); + + it('Checks notebook clone action', async () => { + const renameNotebookMock = jest.fn(() => + Promise.resolve((notebookPutResponse as unknown) as HttpResponse) + ); + const cloneNotebookMock = jest.fn(() => Promise.resolve('dummy-string')); + httpClient.get = jest.fn(() => Promise.resolve((codeBlockNotebook as unknown) as HttpResponse)); + + httpClient.put = jest.fn(() => { + return Promise.resolve((notebookPutResponse as unknown) as HttpResponse); + }); + + httpClient.post = jest.fn(() => { + return Promise.resolve((addCodeBlockResponse as unknown) as HttpResponse); + }); + + const utils = render( + + ); + await waitFor(() => { + expect(utils.getByText('sample-notebook-1')).toBeInTheDocument(); + }); act(() => { fireEvent.click(utils.getByText('Notebook actions')); @@ -329,6 +389,42 @@ describe(' spec', () => { }); expect(cloneNotebookMock).toHaveBeenCalledTimes(1); + }); + + it('Checks notebook delete action', async () => { + const renameNotebookMock = jest.fn(() => + Promise.resolve((notebookPutResponse as unknown) as HttpResponse) + ); + const cloneNotebookMock = jest.fn(() => Promise.resolve('dummy-string')); + httpClient.get = jest.fn(() => Promise.resolve((codeBlockNotebook as unknown) as HttpResponse)); + + httpClient.put = jest.fn(() => { + return Promise.resolve((notebookPutResponse as unknown) as HttpResponse); + }); + + httpClient.post = jest.fn(() => { + return Promise.resolve((addCodeBlockResponse as unknown) as HttpResponse); + }); + + const utils = render( + + ); + await waitFor(() => { + expect(utils.getByText('sample-notebook-1')).toBeInTheDocument(); + }); act(() => { fireEvent.click(utils.getByText('Notebook actions')); @@ -355,7 +451,7 @@ describe(' spec', () => { expect(deleteNotebook).toHaveBeenCalledTimes(1); }); - it('renders the visualization component', async () => { + it('Renders the visualization component', async () => { SavedObjectsActions.getBulk = jest.fn().mockResolvedValue({ observabilityObjectList: [{ savedVisualization: sampleSavedVisualization }], }); diff --git a/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx b/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx index c29adf2f9..2339b9502 100644 --- a/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx +++ b/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx @@ -91,6 +91,5 @@ describe('Testing default backend parser function with wrong schema', () => { expect(() => { const _parsedParagraphs3 = defaultParagraphParser(sampleNotebook5.paragraphs); }).toThrow(Error); - done(); }); }); From 0b31f913e415548a267c651d1155568e3adf108f Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Mon, 8 Jan 2024 14:36:10 -0800 Subject: [PATCH 13/14] updated snapshot Signed-off-by: Shenoy Pratik --- .../__snapshots__/notebook.test.tsx.snap | 360 +++++++++++++++++- 1 file changed, 358 insertions(+), 2 deletions(-) diff --git a/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap b/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap index deb0475bc..b2bc5ba05 100644 --- a/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap +++ b/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[` spec renders the empty component and test reporting action button 1`] = ` +exports[` spec Renders the empty component 1`] = `
@@ -338,7 +338,7 @@ exports[` spec renders the empty component and test reporting action
`; -exports[` spec renders the visualization component 1`] = ` +exports[` spec Renders the visualization component 1`] = `
@@ -650,3 +650,359 @@ exports[` spec renders the visualization component 1`] = `
`; + +exports[` spec test reporting action button 1`] = ` +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+

+ sample-notebook-1 +

+
+
+
+
+
+

+ Created +
+ + 12/14/2023 06:49 PM +

+
+
+
+
+
+
+
+
+
+

+ No paragraphs +

+
+ Add a paragraph to compose your document or story. Notebooks now support two types of input: +
+
+
+
+
+
+
+
+
+ +
+
+ + Code block + +
+

+ Write contents directly using markdown, SQL or PPL. +

+
+
+ +
+
+
+
+
+ +
+
+ + Visualization + +
+

+ Import OpenSearch Dashboards or Observability visualizations to the notes. +

+
+
+ +
+
+
+
+
+
+
+
+
+
+`; From 5ad0dbdbcd828f7b70dbb823f707f1aa00c0564f Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Mon, 8 Jan 2024 15:00:00 -0800 Subject: [PATCH 14/14] atomicized code block checks Signed-off-by: Shenoy Pratik --- .../components/__tests__/notebook.test.tsx | 119 +++++++++++++++++- 1 file changed, 117 insertions(+), 2 deletions(-) diff --git a/public/components/notebooks/components/__tests__/notebook.test.tsx b/public/components/notebooks/components/__tests__/notebook.test.tsx index 999d74ff9..eb33888af 100644 --- a/public/components/notebooks/components/__tests__/notebook.test.tsx +++ b/public/components/notebooks/components/__tests__/notebook.test.tsx @@ -121,7 +121,45 @@ describe(' spec', () => { }); }); - it('Checks code block operations', async () => { + it('Adds a code block', async () => { + httpClient.get = jest.fn(() => Promise.resolve((emptyNotebook as unknown) as HttpResponse)); + let postFlag = 1; + httpClient.post = jest.fn(() => { + if (postFlag === 1) { + postFlag += 1; + return Promise.resolve((addCodeBlockResponse as unknown) as HttpResponse); + } else return Promise.resolve((runCodeBlockResponse as unknown) as HttpResponse); + }); + const utils = render( + + ); + await waitFor(() => { + expect(utils.getByText('sample-notebook-1')).toBeInTheDocument(); + }); + + act(() => { + utils.getByText('Add code block').click(); + }); + + await waitFor(() => { + expect(utils.getByPlaceholderText(codePlaceholderText)).toBeInTheDocument(); + }); + }); + + it('toggles show input in code block', async () => { httpClient.get = jest.fn(() => Promise.resolve((emptyNotebook as unknown) as HttpResponse)); let postFlag = 1; httpClient.post = jest.fn(() => { @@ -165,9 +203,43 @@ describe(' spec', () => { await waitFor(() => { expect(utils.queryByPlaceholderText(codePlaceholderText)).toBeNull(); }); + }); + + it('runs a code block and checks the output', async () => { + httpClient.get = jest.fn(() => Promise.resolve((emptyNotebook as unknown) as HttpResponse)); + let postFlag = 1; + httpClient.post = jest.fn(() => { + if (postFlag === 1) { + postFlag += 1; + return Promise.resolve((addCodeBlockResponse as unknown) as HttpResponse); + } else return Promise.resolve((runCodeBlockResponse as unknown) as HttpResponse); + }); + const utils = render( + + ); + await waitFor(() => { + expect(utils.getByText('sample-notebook-1')).toBeInTheDocument(); + }); act(() => { - utils.getByLabelText('Toggle show input').click(); + utils.getByText('Add code block').click(); + }); + + await waitFor(() => { + expect(utils.getByPlaceholderText(codePlaceholderText)).toBeInTheDocument(); }); act(() => { @@ -181,6 +253,49 @@ describe(' spec', () => { expect(utils.queryByText('Run')).toBeNull(); expect(utils.getByText('hello')).toBeInTheDocument(); }); + }); + + it('toggles between input/output only views', async () => { + httpClient.get = jest.fn(() => Promise.resolve((emptyNotebook as unknown) as HttpResponse)); + const utils = render( + + ); + await waitFor(() => { + expect(utils.getByText('sample-notebook-1')).toBeInTheDocument(); + }); + + act(() => { + utils.getByText('Add code block').click(); + }); + + await waitFor(() => { + expect(utils.getByPlaceholderText(codePlaceholderText)).toBeInTheDocument(); + }); + + act(() => { + utils.getByLabelText('Toggle show input').click(); + }); + + await waitFor(() => { + expect(utils.queryByPlaceholderText(codePlaceholderText)).toBeNull(); + }); + + act(() => { + utils.getByLabelText('Toggle show input').click(); + }); act(() => { fireEvent.click(utils.getByTestId('input_only'));