Skip to content

Commit

Permalink
feat: Add migration generator
Browse files Browse the repository at this point in the history
  • Loading branch information
wasabigeek committed Mar 31, 2021
1 parent 01ffbb3 commit 3c770a5
Show file tree
Hide file tree
Showing 21 changed files with 1,480 additions and 190 deletions.
110 changes: 0 additions & 110 deletions __tests__/pages/index.test.js

This file was deleted.

109 changes: 109 additions & 0 deletions __tests__/pages/migration.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* @jest-environment jsdom
*/

import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { MIGRATION_FORMATS } from "../../helpers/constants";
import MigrationPage from "../../pages/g/migration";

it("renders", async () => {
render(<MigrationPage />);

expect(screen.getByText(/^bin\/rails g migration/)).toBeTruthy();
expect(screen.getByText("AddExampleColumnsToExampleTable")).toBeTruthy();
});

it("sets the Migration", async () => {
render(<MigrationPage />);

const migrationButton = screen.getByText("AddExampleColumnsToExampleTable");
userEvent.click(migrationButton);

const input = screen.getAllByRole("textbox")[0];
userEvent.clear(input);
userEvent.type(input, "DifferentColumns");
// What's a better matcher for this?
expect(screen.getByText("AddDifferentColumnsToExampleTable")).toBeTruthy();
});

it("sets a field", async () => {
render(<MigrationPage />);

const addAttributeButton = screen.getByText("+ Attribute");
userEvent.click(addAttributeButton);

await waitFor(() => screen.getByText("Edit Attribute 1"));
const attributeNameInput = screen.getByLabelText("Name");
userEvent.type(attributeNameInput, "engine");

const fieldTypeInput = screen.getAllByRole("combobox")[0];
userEvent.selectOptions(fieldTypeInput, "references");

const indexTypeInput = screen.getAllByRole("combobox")[1];
userEvent.selectOptions(indexTypeInput, "index");

expect(screen.getByText("engine:references:index")).toBeTruthy();
});

it("toggles args", async () => {
render(<MigrationPage />);
let migrationButton = screen.getByText("AddExampleColumnsToExampleTable");
userEvent.click(migrationButton);
expect(screen.queryByText("Edit Migration")).toBeTruthy();

migrationButton = screen.getByText("AddExampleColumnsToExampleTable");
userEvent.click(migrationButton);
expect(screen.queryByText("Edit Migration")).toBeNull();
});

it("swaps between editors", async () => {
render(<MigrationPage />);

const modelButton = screen.getByText("AddExampleColumnsToExampleTable");
userEvent.click(modelButton);
expect(screen.queryByText("Edit Migration")).toBeTruthy();

const attributeButton = screen.getByText("+ Attribute");
userEvent.click(attributeButton);
expect(screen.queryByText("Edit Attribute 1")).toBeTruthy();
});

it("copies command", async () => {
Object.assign(navigator, {
clipboard: {
writeText: () => {},
},
});
jest.spyOn(navigator.clipboard, "writeText");

render(<MigrationPage />); // refactor to take initialArgs for a more deterministic test

const copyButton = screen.getByText("Copy");
userEvent.click(copyButton);
expect(navigator.clipboard.writeText).toHaveBeenCalledWith(
"bin/rails g migration AddExampleColumnsToExampleTable other_model:references"
);
});

it("copies the right arguments when format is changed", async () => {
Object.assign(navigator, {
clipboard: {
writeText: () => {},
},
});
jest.spyOn(navigator.clipboard, "writeText");

render(<MigrationPage />); // refactor to take initialArgs for a more deterministic test
const migrationButton = screen.getByText("AddExampleColumnsToExampleTable");
userEvent.click(migrationButton);

const formatDropdown = screen.getByLabelText("Format");
userEvent.selectOptions(formatDropdown, MIGRATION_FORMATS.CUSTOM);

const copyButton = screen.getByText("Copy");
userEvent.click(copyButton);
expect(navigator.clipboard.writeText).toHaveBeenCalledWith(
"bin/rails g migration AddExampleColumnsToExampleTable"
);
});
114 changes: 114 additions & 0 deletions __tests__/pages/model.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/**
* @jest-environment jsdom
*/

import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import ModelPage from "../../pages/g/model";

it("renders", async () => {
render(<ModelPage />);

expect(screen.getByText("rails.help")).toBeTruthy();
expect(screen.getByText(/^bin\/rails g/)).toBeTruthy();
expect(screen.getByText("ExampleModel")).toBeTruthy();
expect(
screen.getByText("other_model:references{polymorphic}:uniq")
).toBeTruthy();
});

it("sets the model", async () => {
render(<ModelPage />);

const modelButton = screen.getByText("ExampleModel");
userEvent.click(modelButton);

await waitFor(() => screen.getByLabelText("Name"));
const modelInput = screen.getByLabelText("Name");
userEvent.clear(modelInput);
userEvent.type(modelInput, "car");
// What's a better matcher for this?
expect(screen.getByText("car")).toBeTruthy();
});

it("sets a field", async () => {
render(<ModelPage />);

const addAttributeButton = screen.getByText("+ Attribute");
userEvent.click(addAttributeButton);

await waitFor(() => screen.getByText("Edit Attribute 1"));
const attributeNameInput = screen.getByLabelText("Name");
userEvent.type(attributeNameInput, "engine");

const fieldTypeInput = screen.getAllByRole("combobox")[0];
userEvent.selectOptions(fieldTypeInput, "references");

const indexTypeInput = screen.getAllByRole("combobox")[1];
userEvent.selectOptions(indexTypeInput, "index");

expect(screen.getByText("engine:references:index")).toBeTruthy();
});

it("sets the parent", async () => {
render(<ModelPage />);

const button = screen.getByText("--parent");
userEvent.click(button);

await waitFor(() => screen.getByText("Edit Parent Model"));
const nameInput = screen.getByLabelText("Name");
userEvent.type(nameInput, "Woohoo");

expect(screen.getByText("--parent Woohoo")).toBeTruthy();
});

it("toggles args", async () => {
render(<ModelPage />);
let modelButton = screen.getByText("ExampleModel");
userEvent.click(modelButton);
expect(screen.queryByText("Edit Model")).toBeTruthy();

modelButton = screen.getByText("ExampleModel");
userEvent.click(modelButton);
expect(screen.queryByText("Edit Model")).toBeNull();
});

it("swaps between editors", async () => {
render(<ModelPage />);

const modelButton = screen.getByText("ExampleModel");
userEvent.click(modelButton);
expect(screen.queryByText("Edit Model")).toBeTruthy();
expect(screen.queryByText(/Edit Attribute/)).toBeNull();
expect(screen.queryByText("Edit Parent Model")).toBeNull();

const attributeButton = screen.getByText("+ Attribute");
userEvent.click(attributeButton);
expect(screen.queryByText("Edit Model")).toBeNull();
expect(screen.queryByText("Edit Attribute 1")).toBeTruthy();
expect(screen.queryByText("Edit Parent Model")).toBeNull();

const parentButton = screen.getByText("--parent");
userEvent.click(parentButton);
expect(screen.queryByText("Edit Model")).toBeNull();
expect(screen.queryByText(/Edit Attribute/)).toBeNull();
expect(screen.queryByText("Edit Parent Model")).toBeTruthy();
});

it("copies command", async () => {
Object.assign(navigator, {
clipboard: {
writeText: () => {},
},
});
jest.spyOn(navigator.clipboard, "writeText");

render(<ModelPage />); // refactor to take initialArgs for a more deterministic test

const copyButton = screen.getByText("Copy");
userEvent.click(copyButton);
expect(navigator.clipboard.writeText).toHaveBeenCalledWith(
"bin/rails g model ExampleModel other_model:references{polymorphic}:uniq"
);
});
39 changes: 39 additions & 0 deletions components/CopyButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useState } from "react";
import Pill from "./Pill";

const CopyButton = ({ text }) => {
const [showCopying, setShowCopying] = useState(false);

const copyToClipboard = () => {
setShowCopying(true);
navigator.clipboard.writeText(text);
setTimeout(() => setShowCopying(false), 2000);
};

return (
<Pill
text={showCopying ? "Copied!" : "Copy"}
baseColor="gray"
onClick={copyToClipboard}
editable={false}
leftIcon={
<svg
className={`mr-2 h-5 w-5 text-gray-500 inline`}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"
/>
</svg>
}
/>
);
};

export default CopyButton;
21 changes: 21 additions & 0 deletions components/CopyButton.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* @jest-environment jsdom
*/

import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import CopyButton from "./CopyButton";

it("copies command", async () => {
Object.assign(navigator, {
clipboard: {
writeText: () => {},
},
});
jest.spyOn(navigator.clipboard, "writeText");

render(<CopyButton text="Sample Text" />);
const copyButton = screen.getByText("Copy");
userEvent.click(copyButton);
expect(navigator.clipboard.writeText).toHaveBeenCalledWith("Sample Text");
});
Loading

0 comments on commit 3c770a5

Please sign in to comment.