diff --git a/packages/compass-components/src/components/document-list/document.spec.tsx b/packages/compass-components/src/components/document-list/document.spec.tsx new file mode 100644 index 00000000000..5aab0a0e56c --- /dev/null +++ b/packages/compass-components/src/components/document-list/document.spec.tsx @@ -0,0 +1,122 @@ +import React from 'react'; +import { expect } from 'chai'; +import { render, cleanup, screen, within } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import HadronDocument from 'hadron-document'; +import Document from './document'; + +describe('Document', function () { + let doc: HadronDocument; + beforeEach(function () { + doc = new HadronDocument({ str: 'abc', num: 123, date: new Date(0) }); + }); + + afterEach(cleanup); + + it('should render HadronDocument keys and values', function () { + render(); + expect(screen.getByText('str')).to.exist; + expect(screen.getByTitle('abc')).to.exist; + + expect(screen.getByText('num')).to.exist; + expect(screen.getByTitle('123')).to.exist; + + expect(screen.getByText('date')).to.exist; + expect(screen.getByTitle('1970-01-01T00:00:00.000+00:00')).to.exist; + }); + + describe('edit mode', function () { + it('should change element key name on edit', function () { + render(); + + const el = document.querySelector( + `[data-id="${doc.get('str').uuid}"]` + ); + const keyEditor = within(el).getByTestId('hadron-document-key-editor'); + + userEvent.clear(keyEditor); + userEvent.keyboard('new_name'); + userEvent.tab(); + + expect(screen.getByDisplayValue('new_name')).to.exist; + + expect(doc.get('new_name').key).to.eq('str'); + expect(doc.get('new_name').currentKey).to.eq('new_name'); + }); + + it('should change element string value on edit', function () { + render(); + + const el = document.querySelector( + `[data-id="${doc.get('str').uuid}"]` + ); + + const valueEditor = within(el).getByTestId( + 'hadron-document-value-editor' + ); + + userEvent.clear(valueEditor); + userEvent.keyboard('bla'); + userEvent.tab(); + + expect(doc.get('str').currentValue).to.eq('bla'); + expect(doc.get('str').currentType).to.eq('String'); + }); + + it('should change element number value on edit', function () { + render(); + + const el = document.querySelector( + `[data-id="${doc.get('num').uuid}"]` + ); + + const valueEditor = within(el).getByTestId( + 'hadron-document-value-editor' + ); + + userEvent.clear(valueEditor); + userEvent.keyboard('321'); + userEvent.tab(); + + expect(doc.get('num').currentValue.valueOf()).to.eq(321); + expect(doc.get('num').currentType).to.eq('Int32'); + }); + + it('should change element date value on edit', function () { + render(); + + const el = document.querySelector( + `[data-id="${doc.get('date').uuid}"]` + ); + + const valueEditor = within(el).getByTestId( + 'hadron-document-value-editor' + ); + + userEvent.clear(valueEditor); + userEvent.keyboard('2000-01-01'); + userEvent.tab(); + + expect((doc.get('date').currentValue as Date).toISOString()).to.eq( + '2000-01-01T00:00:00.000Z' + ); + expect(doc.get('date').currentType).to.eq('Date'); + }); + + it('should change element type on edit', function () { + render(); + + const el = document.querySelector( + `[data-id="${doc.get('num').uuid}"]` + ); + + const typeEditor = within(el).getByTestId('hadron-document-type-editor'); + + userEvent.selectOptions(typeEditor, 'String'); + userEvent.tab(); + + expect(doc.get('num').currentValue.valueOf()).to.eq('123'); + expect(doc.get('num').currentType).to.eq('String'); + }); + }); +}); diff --git a/packages/compass-components/src/components/document-list/document.tsx b/packages/compass-components/src/components/document-list/document.tsx index e253b484f42..01bbb4b710d 100644 --- a/packages/compass-components/src/components/document-list/document.tsx +++ b/packages/compass-components/src/components/document-list/document.tsx @@ -57,17 +57,17 @@ const hadronDocument = css({ const HadronDocument: React.FunctionComponent<{ value: HadronDocumentType; visibleFieldsCount?: number; - expanded: boolean; - editable: boolean; + expanded?: boolean; + editable?: boolean; + editing?: boolean; onEditStart?: () => void; - editing: boolean; }> = ({ value: document, visibleFieldsCount, - expanded, - editable, + expanded = false, + editable = false, + editing = false, onEditStart, - editing, }) => { const { elements } = useHadronDocument(document); const visibleElements = useMemo(() => { diff --git a/packages/compass-components/src/components/document-list/element-editors.tsx b/packages/compass-components/src/components/document-list/element-editors.tsx index 01c2b75df44..f18bb0695c0 100644 --- a/packages/compass-components/src/components/document-list/element-editors.tsx +++ b/packages/compass-components/src/components/document-list/element-editors.tsx @@ -158,8 +158,10 @@ export const ValueEditor: React.FunctionComponent<{ valid: boolean; validationMessage: string | null; originalValue: TypeCastMap[keyof TypeCastMap]; - onChange(newVal: string): void; autoFocus?: boolean; + onChange(newVal: string): void; + onFocus(): void; + onBlur(): void; }> = ({ editing, onEditStart, @@ -168,8 +170,10 @@ export const ValueEditor: React.FunctionComponent<{ valid, validationMessage, originalValue, - onChange, autoFocus, + onChange, + onFocus, + onBlur, }) => { const val = String(value); @@ -230,6 +234,8 @@ export const ValueEditor: React.FunctionComponent<{ onChange={(evt) => { onChange(evt.currentTarget.value); }} + onFocus={onFocus} + onBlur={onBlur} // eslint-disable-next-line jsx-a11y/no-autofocus autoFocus={autoFocus} className={cx( @@ -251,6 +257,8 @@ export const ValueEditor: React.FunctionComponent<{ onChange={(evt) => { onChange(evt.currentTarget.value); }} + onFocus={onFocus} + onBlur={onBlur} // eslint-disable-next-line jsx-a11y/no-autofocus autoFocus={autoFocus} className={cx( diff --git a/packages/compass-components/src/components/document-list/element.tsx b/packages/compass-components/src/components/document-list/element.tsx index e7a14190452..cb6c6f195c3 100644 --- a/packages/compass-components/src/components/document-list/element.tsx +++ b/packages/compass-components/src/components/document-list/element.tsx @@ -139,6 +139,8 @@ function useHadronElement(el: HadronElementType) { el.currentType !== 'Array', valid: isValid, validationMessage: !isValid ? el.invalidTypeMessage ?? null : null, + startEdit: editor.start.bind(editor), + completeEdit: editor.complete.bind(editor), }, type: { value: el.currentType, @@ -486,6 +488,12 @@ export const HadronElement: React.FunctionComponent<{ onEditStart={() => { onEditStart?.(element.uuid, 'value'); }} + onFocus={() => { + value.startEdit(); + }} + onBlur={() => { + value.completeEdit(); + }} > ) : (