Skip to content

Commit

Permalink
🪟 🔧 Add testing and storybook component for CatalogDiffModal (#15426)
Browse files Browse the repository at this point in the history
* wip diff modal test setup

* starting storybook add

* storybook working now

* cleanup

* aria labels

* test syncmode string
  • Loading branch information
teallarson authored Aug 10, 2022
1 parent 2f17e99 commit a65524a
Show file tree
Hide file tree
Showing 9 changed files with 363 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -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(
<IntlProvider messages={messages} locale="en">
<CatalogDiffModal
catalogDiff={mockCatalogDiff}
catalog={mockCatalog}
onClose={() => {
return null;
}}
/>
</IntlProvider>
);

/**
* 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(
<IntlProvider messages={messages} locale="en">
<CatalogDiffModal
catalogDiff={mockCatalogDiff}
catalog={mockCatalog}
onClose={() => {
return null;
}}
/>
</IntlProvider>
);

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(
<IntlProvider messages={messages} locale="en">
<CatalogDiffModal
catalogDiff={mockCatalogDiff}
catalog={mockCatalog}
onClose={() => {
return null;
}}
/>
</IntlProvider>
);

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(
<IntlProvider messages={messages} locale="en">
<CatalogDiffModal
catalogDiff={mockCatalogDiff}
catalog={mockCatalog}
onClose={() => {
return null;
}}
/>
</IntlProvider>
);

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 = [];
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const DiffAccordion: React.FC<DiffAccordionProps> = ({ streamTransform })
<Disclosure>
{({ open }) => (
<>
<Disclosure.Button className={styles.accordionButton}>
<Disclosure.Button className={styles.accordionButton} aria-label="toggle accordion">
<DiffAccordionHeader
streamDescriptor={streamTransform.streamDescriptor}
removedCount={removedItems.length}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ interface DiffFieldTableProps {

export const DiffFieldTable: React.FC<DiffFieldTableProps> = ({ fieldTransforms, diffVerb }) => {
return (
<table className={styles.table}>
<table className={styles.table} aria-label={`${diffVerb} fields`}>
<thead>
<tr className={styles.accordionSubHeader}>
<th>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ export const DiffIconBlock: React.FC<DiffIconBlockProps> = ({ 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 }),
}
)}`}
/>
Expand All @@ -35,13 +35,13 @@ export const DiffIconBlock: React.FC<DiffIconBlockProps> = ({ 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 }),
}
)}`}
/>
Expand All @@ -51,13 +51,13 @@ export const DiffIconBlock: React.FC<DiffIconBlockProps> = ({ 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 }),
}
)}`}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const DiffSection: React.FC<DiffSectionProps> = ({ streams, catalog, diff
<div className={styles.sectionHeader}>
<DiffHeader diffCount={streams.length} diffVerb={diffVerb} diffType="stream" />
</div>
<table>
<table aria-label={`${diffVerb} streams table`}>
<thead className={styles.sectionSubHeader}>
<tr>
<th>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const FieldRow: React.FC<FieldRowProps> = ({ 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",
Expand All @@ -50,16 +50,16 @@ export const FieldRow: React.FC<FieldRowProps> = ({ transform }) => {
)}
</td>
<td className={contentStyle}>
<td className={styles.cell}>
<div className={styles.cell}>
<span>{fieldName}</span>
</td>
<td className={updateCellStyle}>
</div>
<div className={updateCellStyle}>
{oldType && newType && (
<span>
{oldType} <FontAwesomeIcon icon={faArrowRight} /> {newType}
</span>
)}
</td>
</div>
</td>
</tr>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,15 @@ export const FieldSection: React.FC<FieldSectionProps> = ({ streams, diffVerb })
</div>
<div className={styles.fieldRowsContainer}>
{streams.length > 0 && (
<ul>
<ul
aria-label={formatMessage(
{ id: "connection.updateSchema.changed" },
{
value: streams.length,
item: formatMessage({ id: "connection.updateSchema.stream" }, { count: streams.length }),
}
)}
>
{streams.map((stream) => {
return (
<li key={`${stream.streamDescriptor.namespace}.${stream.streamDescriptor.name}`}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const StreamRow: React.FC<StreamRowProps> = ({ streamTransform, syncMode,
)}
</td>
<td className={styles.nameCell}>{namespace}</td>
<td className={styles.nameCell}>{itemName}</td>{" "}
<td className={styles.nameCell}>{itemName}</td>
<td>{diffVerb === "removed" && syncMode && <SyncModeBox syncModeString={syncMode} />} </td>
</tr>
);
Expand Down
Loading

0 comments on commit a65524a

Please sign in to comment.