From a65524af2c3917c71844916eaa845f1f815ad9fa Mon Sep 17 00:00:00 2001 From: Teal Larson Date: Wed, 10 Aug 2022 16:03:59 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=AA=9F=20=F0=9F=94=A7=20Add=20testing=20a?= =?UTF-8?q?nd=20storybook=20component=20for=20CatalogDiffModal=20(#15426)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * wip diff modal test setup * starting storybook add * storybook working now * cleanup * aria labels * test syncmode string --- .../CatalogDiffModal.test.tsx | 265 ++++++++++++++++++ .../components/DiffAccordion.tsx | 2 +- .../components/DiffFieldTable.tsx | 2 +- .../components/DiffIconBlock.tsx | 12 +- .../components/DiffSection.tsx | 2 +- .../CatalogDiffModal/components/FieldRow.tsx | 10 +- .../components/FieldSection.tsx | 10 +- .../CatalogDiffModal/components/StreamRow.tsx | 2 +- .../CatalogDiffModal/index.stories.tsx | 74 +++++ 9 files changed, 363 insertions(+), 16 deletions(-) create mode 100644 airbyte-webapp/src/views/Connection/CatalogDiffModal/CatalogDiffModal.test.tsx create mode 100644 airbyte-webapp/src/views/Connection/CatalogDiffModal/index.stories.tsx diff --git a/airbyte-webapp/src/views/Connection/CatalogDiffModal/CatalogDiffModal.test.tsx b/airbyte-webapp/src/views/Connection/CatalogDiffModal/CatalogDiffModal.test.tsx new file mode 100644 index 0000000000000..8f025a281d077 --- /dev/null +++ b/airbyte-webapp/src/views/Connection/CatalogDiffModal/CatalogDiffModal.test.tsx @@ -0,0 +1,265 @@ +import { cleanup, render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { IntlProvider } from "react-intl"; + +import { + AirbyteCatalog, + CatalogDiff, + DestinationSyncMode, + StreamTransform, + SyncMode, +} from "core/request/AirbyteClient"; + +import messages from "../../../locales/en.json"; +import { CatalogDiffModal } from "./CatalogDiffModal"; + +const mockCatalogDiff: CatalogDiff = { + transforms: [], +}; + +const removedItems: StreamTransform[] = [ + { + transformType: "remove_stream", + streamDescriptor: { namespace: "apple", name: "dragonfruit" }, + }, + { + transformType: "remove_stream", + streamDescriptor: { namespace: "apple", name: "eclair" }, + }, + { + transformType: "remove_stream", + streamDescriptor: { namespace: "apple", name: "fishcake" }, + }, + { + transformType: "remove_stream", + streamDescriptor: { namespace: "apple", name: "gelatin_mold" }, + }, +]; + +const addedItems: StreamTransform[] = [ + { + transformType: "add_stream", + streamDescriptor: { namespace: "apple", name: "banana" }, + }, + { + transformType: "add_stream", + streamDescriptor: { namespace: "apple", name: "carrot" }, + }, +]; + +const updatedItems: StreamTransform[] = [ + { + transformType: "update_stream", + streamDescriptor: { namespace: "apple", name: "harissa_paste" }, + updateStream: [ + { transformType: "add_field", fieldName: ["users", "phone"] }, + { transformType: "add_field", fieldName: ["users", "email"] }, + { transformType: "remove_field", fieldName: ["users", "lastName"] }, + + { + transformType: "update_field_schema", + fieldName: ["users", "address"], + updateFieldSchema: { oldSchema: { type: "number" }, newSchema: { type: "string" } }, + }, + ], + }, +]; + +const mockCatalog: AirbyteCatalog = { + streams: [ + { + stream: { + namespace: "apple", + name: "banana", + }, + config: { + syncMode: SyncMode.full_refresh, + destinationSyncMode: DestinationSyncMode.overwrite, + }, + }, + { + stream: { + namespace: "apple", + name: "carrot", + }, + config: { + syncMode: SyncMode.full_refresh, + destinationSyncMode: DestinationSyncMode.overwrite, + }, + }, + { + stream: { + namespace: "apple", + name: "dragonfruit", + }, + config: { + syncMode: SyncMode.full_refresh, + destinationSyncMode: DestinationSyncMode.overwrite, + }, + }, + { + stream: { + namespace: "apple", + name: "eclair", + }, + config: { + syncMode: SyncMode.full_refresh, + destinationSyncMode: DestinationSyncMode.overwrite, + }, + }, + { + stream: { + namespace: "apple", + name: "fishcake", + }, + config: { + syncMode: SyncMode.incremental, + destinationSyncMode: DestinationSyncMode.append_dedup, + }, + }, + { + stream: { + namespace: "apple", + name: "gelatin_mold", + }, + config: { + syncMode: SyncMode.incremental, + destinationSyncMode: DestinationSyncMode.append_dedup, + }, + }, + { + stream: { + namespace: "apple", + name: "harissa_paste", + }, + config: { + syncMode: SyncMode.full_refresh, + destinationSyncMode: DestinationSyncMode.overwrite, + }, + }, + ], +}; + +describe("catalog diff modal", () => { + afterEach(cleanup); + beforeEach(() => { + mockCatalogDiff.transforms = []; + }); + + test("it renders the correct section for each type of transform", () => { + mockCatalogDiff.transforms.push(...addedItems, ...removedItems, ...updatedItems); + + render( + + { + return null; + }} + /> + + ); + + /** + * tests for: + * - proper sections being created + * - syncmode string is only rendered for removed streams + */ + + const newStreamsTable = screen.getByRole("table", { name: /new streams/ }); + expect(newStreamsTable).toBeInTheDocument(); + + const newStreamRow = screen.getByRole("row", { name: "apple banana" }); + expect(newStreamRow).toBeInTheDocument(); + + const newStreamRowWithSyncMode = screen.queryByRole("row", { name: "apple carrot incremental | append_dedup" }); + expect(newStreamRowWithSyncMode).not.toBeInTheDocument(); + + const removedStreamsTable = screen.getByRole("table", { name: /removed streams/ }); + expect(removedStreamsTable).toBeInTheDocument(); + + const removedStreamRowWithSyncMode = screen.getByRole("row", { + name: "apple dragonfruit full_refresh | overwrite", + }); + expect(removedStreamRowWithSyncMode).toBeInTheDocument(); + + const updatedStreamsSection = screen.getByRole("list", { name: /table with changes/ }); + expect(updatedStreamsSection).toBeInTheDocument(); + + const updatedStreamRowWithSyncMode = screen.queryByRole("row", { + name: "apple harissa_paste full_refresh | overwrite", + }); + expect(updatedStreamRowWithSyncMode).not.toBeInTheDocument(); + }); + + test("added fields are not rendered when not in the diff", () => { + mockCatalogDiff.transforms.push(...removedItems, ...updatedItems); + + render( + + { + return null; + }} + /> + + ); + + const newStreamsTable = screen.queryByRole("table", { name: /new streams/ }); + expect(newStreamsTable).not.toBeInTheDocument(); + }); + + test("removed fields are not rendered when not in the diff", () => { + mockCatalogDiff.transforms.push(...addedItems, ...updatedItems); + + render( + + { + return null; + }} + /> + + ); + + const removedStreamsTable = screen.queryByRole("table", { name: /removed streams/ }); + expect(removedStreamsTable).not.toBeInTheDocument(); + }); + + test("changed streams accordion opens/closes on clicking the description row", () => { + mockCatalogDiff.transforms.push(...addedItems, ...updatedItems); + + render( + + { + return null; + }} + /> + + ); + + const accordionHeader = screen.getByRole("button", { name: /toggle accordion/ }); + + expect(accordionHeader).toBeInTheDocument(); + + const nullAccordionBody = screen.queryByRole("table", { name: /removed fields/ }); + expect(nullAccordionBody).not.toBeInTheDocument(); + + userEvent.click(accordionHeader); + const openAccordionBody = screen.getByRole("table", { name: /removed fields/ }); + expect(openAccordionBody).toBeInTheDocument(); + + userEvent.click(accordionHeader); + const nullAccordionBodyAgain = screen.queryByRole("table", { name: /removed fields/ }); + expect(nullAccordionBodyAgain).not.toBeInTheDocument(); + mockCatalogDiff.transforms = []; + }); +}); diff --git a/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/DiffAccordion.tsx b/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/DiffAccordion.tsx index d42a051c03b99..112563dba001e 100644 --- a/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/DiffAccordion.tsx +++ b/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/DiffAccordion.tsx @@ -23,7 +23,7 @@ export const DiffAccordion: React.FC = ({ streamTransform }) {({ open }) => ( <> - + = ({ fieldTransforms, diffVerb }) => { return ( - +
diff --git a/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/DiffIconBlock.tsx b/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/DiffIconBlock.tsx index 453f23443dcff..a206a18fd5f2d 100644 --- a/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/DiffIconBlock.tsx +++ b/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/DiffIconBlock.tsx @@ -19,13 +19,13 @@ export const DiffIconBlock: React.FC = ({ newCount, removedC num={removedCount} color="red" light - ariaLabel={`${removedCount} ${formatMessage( + ariaLabel={`${formatMessage( { id: "connection.updateSchema.removed", }, { value: removedCount, - item: formatMessage({ id: "field" }, { values: { count: removedCount } }), + item: formatMessage({ id: "connection.updateSchema.field" }, { count: removedCount }), } )}`} /> @@ -35,13 +35,13 @@ export const DiffIconBlock: React.FC = ({ newCount, removedC num={newCount} color="green" light - ariaLabel={`${newCount} ${formatMessage( + ariaLabel={`${formatMessage( { id: "connection.updateSchema.new", }, { value: newCount, - item: formatMessage({ id: "field" }, { values: { count: newCount } }), + item: formatMessage({ id: "connection.updateSchema.field" }, { count: newCount }), } )}`} /> @@ -51,13 +51,13 @@ export const DiffIconBlock: React.FC = ({ newCount, removedC num={changedCount} color="blue" light - ariaLabel={`${changedCount} ${formatMessage( + ariaLabel={`${formatMessage( { id: "connection.updateSchema.changed", }, { value: changedCount, - item: formatMessage({ id: "field" }, { values: { count: changedCount } }), + item: formatMessage({ id: "connection.updateSchema.field" }, { count: changedCount }), } )}`} /> diff --git a/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/DiffSection.tsx b/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/DiffSection.tsx index 47981779d2d9b..cd82648fdee96 100644 --- a/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/DiffSection.tsx +++ b/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/DiffSection.tsx @@ -31,7 +31,7 @@ export const DiffSection: React.FC = ({ streams, catalog, diff
- +
- + ); diff --git a/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/FieldSection.tsx b/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/FieldSection.tsx index 4c03fcf8a4e7b..f6d150fb80b16 100644 --- a/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/FieldSection.tsx +++ b/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/FieldSection.tsx @@ -32,7 +32,15 @@ export const FieldSection: React.FC = ({ streams, diffVerb })
{streams.length > 0 && ( -
    +
      {streams.map((stream) => { return (
    • diff --git a/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/StreamRow.tsx b/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/StreamRow.tsx index 2931ed5ed644b..de077b279de8c 100644 --- a/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/StreamRow.tsx +++ b/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/StreamRow.tsx @@ -45,7 +45,7 @@ export const StreamRow: React.FC = ({ streamTransform, syncMode, )}
- {" "} + ); diff --git a/airbyte-webapp/src/views/Connection/CatalogDiffModal/index.stories.tsx b/airbyte-webapp/src/views/Connection/CatalogDiffModal/index.stories.tsx new file mode 100644 index 0000000000000..ca2181e4a465b --- /dev/null +++ b/airbyte-webapp/src/views/Connection/CatalogDiffModal/index.stories.tsx @@ -0,0 +1,74 @@ +import { ComponentStory, ComponentMeta } from "@storybook/react"; +import { FormattedMessage } from "react-intl"; + +import Modal from "components/Modal"; + +import { CatalogDiffModal } from "./CatalogDiffModal"; + +export default { + title: "Ui/CatalogDiffModal", + component: CatalogDiffModal, +} as ComponentMeta; + +const Template: ComponentStory = (args) => { + return ( + }> + { + return null; + }} + /> + + ); +}; + +export const Primary = Template.bind({}); + +Primary.args = { + catalogDiff: { + transforms: [ + { + transformType: "update_stream", + streamDescriptor: { namespace: "apple", name: "harissa_paste" }, + updateStream: [ + { transformType: "add_field", fieldName: ["users", "phone"] }, + { transformType: "add_field", fieldName: ["users", "email"] }, + { transformType: "remove_field", fieldName: ["users", "lastName"] }, + + { + transformType: "update_field_schema", + fieldName: ["users", "address"], + updateFieldSchema: { oldSchema: { type: "number" }, newSchema: { type: "string" } }, + }, + ], + }, + { + transformType: "add_stream", + streamDescriptor: { namespace: "apple", name: "banana" }, + }, + { + transformType: "add_stream", + streamDescriptor: { namespace: "apple", name: "carrot" }, + }, + { + transformType: "remove_stream", + streamDescriptor: { namespace: "apple", name: "dragonfruit" }, + }, + { + transformType: "remove_stream", + streamDescriptor: { namespace: "apple", name: "eclair" }, + }, + { + transformType: "remove_stream", + streamDescriptor: { namespace: "apple", name: "fishcake" }, + }, + { + transformType: "remove_stream", + streamDescriptor: { namespace: "apple", name: "gelatin_mold" }, + }, + ], + }, + catalog: { streams: [] }, +};
diff --git a/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/FieldRow.tsx b/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/FieldRow.tsx index 1c77e9a7281af..3f8d715c59065 100644 --- a/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/FieldRow.tsx +++ b/airbyte-webapp/src/views/Connection/CatalogDiffModal/components/FieldRow.tsx @@ -28,7 +28,7 @@ export const FieldRow: React.FC = ({ transform }) => { [styles.mod]: diffType === "update", }); - const contentStyle = classnames(styles.content, { + const contentStyle = classnames(styles.content, styles.cell, { [styles.add]: diffType === "add", [styles.remove]: diffType === "remove", [styles.update]: diffType === "update", @@ -50,16 +50,16 @@ export const FieldRow: React.FC = ({ transform }) => { )} - +
{fieldName} -
+ +
{oldType && newType && ( {oldType} {newType} )} -
{namespace}{itemName}{itemName} {diffVerb === "removed" && syncMode && }