Skip to content

Commit

Permalink
Add svelte action tests
Browse files Browse the repository at this point in the history
  • Loading branch information
acurrieclark committed Jan 10, 2024
1 parent a3d6240 commit 33188b8
Show file tree
Hide file tree
Showing 20 changed files with 2,688 additions and 203 deletions.
2,232 changes: 2,037 additions & 195 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@
},
"devDependencies": {
"@onsetsoftware/entity-state": "^0.0.2",
"@testing-library/jest-dom": "^6.2.0",
"@testing-library/svelte": "^4.0.5",
"@testing-library/user-event": "^14.5.2",
"@types/diff": "^5.0.2",
"jsdom": "^23.2.0",
"svelte-preprocess": "^5.1.3",
"typescript": "^5.0.0",
"vite": "^5.0.0",
"vite-plugin-dts": "^3.0.0",
Expand Down
4 changes: 2 additions & 2 deletions src/actions/bind-entity-int-deferred.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ export function bindEntityIntDeferred<
return doc;
});
},
changeListener: (node, { store, ids, path, title }) => {
if (!changed) {
changeListener: (node, { store, ids, path, title, manualSave }) => {
if (!changed || manualSave) {
return;
}

Expand Down
4 changes: 2 additions & 2 deletions src/actions/bind-entity-string-deferred.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ export function bindEntityStringDeferred<
});
},
changeListener: (node, options) => {
const { store, ids, path, title } = options;
const { store, ids, path, title, manualSave } = options;

if (!changed) {
if (!changed || manualSave) {
return;
}

Expand Down
4 changes: 2 additions & 2 deletions src/actions/bind-entity-value-deferred.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ export function bindEntityValueDeferred<
return doc;
});
},
changeListener: (node, { store, ids, path, title }) => {
if (!changed) {
changeListener: (node, { store, ids, path, title, manualSave }) => {
if (!changed || manualSave) {
return;
}

Expand Down
4 changes: 4 additions & 0 deletions src/actions/types/automerge-svelte-input.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface AutomergeSvelteInput extends HTMLInputElement {
cancel: () => void;
save: () => void;
}
1 change: 1 addition & 0 deletions src/actions/types/bind-entity-options.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export type BindEntityOptions<
ids: GetIdType<T>[];
path: Path<T>;
title?: string;
manualSave?: boolean;
};
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ export { AutomergeSvelteStore } from "./automerge-svelte-store";
export type { AutomergeSvelteStoreInterface } from "./automerge-svelte-store.type";

export type { EntityTitles } from "./automerge-entity-store";

export type { AutomergeSvelteInput } from "./actions/types/automerge-svelte-input.type";
50 changes: 50 additions & 0 deletions tests/actions/bind-checked.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { beforeEach, describe, expect, test } from "vitest";
import { render, screen } from "@testing-library/svelte";
import ActionsComponent from "./setup/ActionsComponent.svelte";
import { AutomergeStore } from "@onsetsoftware/automerge-store";
import type { DocumentShape } from "./setup/document.type";
import { AutomergeSvelteStore } from "../../src";
import { next as A } from "@automerge/automerge";
import { document } from "./setup/document";

describe("bind-checked", async () => {
let root: AutomergeStore<DocumentShape>;
let store: AutomergeSvelteStore<DocumentShape>;
beforeEach(async () => {
root = new AutomergeStore<DocumentShape>("actions-store", A.from(document));

store = new AutomergeSvelteStore(root);

render(ActionsComponent, { props: { store } });
});

test("updating a checkbox updates the store", async () => {
const checkbox = screen.getByLabelText("checked");
expect(checkbox).not.toBeChecked();

expect(store.get()?.checked).toBe(false);
expect(root.doc?.checked).toBe(false);

checkbox.click();
expect(checkbox).toBeChecked();

expect(store.get()?.checked).toBe(true);
expect(root.doc?.checked).toBe(true);
});

test("updating the store updates the checkbox", async () => {
const checkbox = screen.getByLabelText("checked");
expect(checkbox).not.toBeChecked();

expect(store.get()?.checked).toBe(false);
expect(root.doc?.checked).toBe(false);

store.change((doc) => {
doc.checked = true;
});
expect(checkbox).toBeChecked();

expect(store.get()?.checked).toBe(true);
expect(root.doc?.checked).toBe(true);
});
});
76 changes: 76 additions & 0 deletions tests/actions/bind-deferred.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { next as A } from "@automerge/automerge";
import { AutomergeStore } from "@onsetsoftware/automerge-store";
import { render, screen } from "@testing-library/svelte";
import userEvent from "@testing-library/user-event";
import { get } from "svelte/store";
import { beforeEach, describe, expect, test } from "vitest";
import { AutomergeSvelteStore } from "../../src";
import ActionsComponent from "./setup/ActionsComponent.svelte";
import { document } from "./setup/document";
import type { DocumentShape } from "./setup/document.type";

describe("bind value/string deferred", async () => {
let root: AutomergeStore<DocumentShape>;
let store: AutomergeSvelteStore<DocumentShape>;
beforeEach(async () => {
root = new AutomergeStore<DocumentShape>("actions-store", A.from(document));

store = new AutomergeSvelteStore(root);

render(ActionsComponent, { props: { store } });
});

["Value Deferred Input", "String Deferred Input"].forEach((label) => {
test("updating the text input value updates the store", async () => {
const user = userEvent.setup();
const input: HTMLInputElement = screen.getByLabelText(label);

expect(input.value).toBe("foo");

expect(store.get()?.data.value).toBe("foo");
expect(root.doc?.data.value).toBe("foo");

let count = 0;

const final = "foo bar";

const localChangesComplete = new Promise<void>((resolve) => {
const unsub = store.subscribe((doc) => {
expect(doc.data.value).toBe(final.substring(0, count + 3));

count++;
if (count === 5) {
unsub();
resolve();
}
});
});

input.focus();
await user.type(input, " bar");
expect(input.value).toBe("foo bar");

expect(get(store).data.value).toBe("foo bar");

await localChangesComplete;

expect(store.get()?.data.value).toBe("foo");
expect(root.doc?.data.value).toBe("foo");
input.blur();

expect(store.get()?.data.value).toBe("foo bar");
expect(root.doc?.data.value).toBe("foo bar");
});

test("updating the store updates the value", async () => {
const input: HTMLInputElement = screen.getByLabelText(label);
expect(input.value).toBe("foo");

store.change((doc) => {
doc.data.value = "foo bar";
});

expect(input.value).toBe("foo bar");
});
});
});
50 changes: 50 additions & 0 deletions tests/actions/bind-value.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { beforeEach, describe, expect, test } from "vitest";
import userEvent from "@testing-library/user-event";
import { render, screen } from "@testing-library/svelte";
import ActionsComponent from "./setup/ActionsComponent.svelte";
import { AutomergeStore } from "@onsetsoftware/automerge-store";
import type { DocumentShape } from "./setup/document.type";
import { AutomergeSvelteStore } from "../../src";
import { next as A } from "@automerge/automerge";
import { document } from "./setup/document";

describe("bind value/string", async () => {
let root: AutomergeStore<DocumentShape>;
let store: AutomergeSvelteStore<DocumentShape>;
beforeEach(async () => {
root = new AutomergeStore<DocumentShape>("actions-store", A.from(document));

store = new AutomergeSvelteStore(root);

render(ActionsComponent, { props: { store } });
});

["Value Input", "String Input"].forEach((label) => {
test("updating the text input value updates the store", async () => {
const user = userEvent.setup();
const input: HTMLInputElement = screen.getByLabelText(label);
expect(input.value).toBe("foo");

expect(store.get()?.data.value).toBe("foo");
expect(root.doc?.data.value).toBe("foo");

input.focus();
await user.type(input, " bar");
expect(input.value).toBe("foo bar");

expect(store.get()?.data.value).toBe("foo bar");
expect(root.doc?.data.value).toBe("foo bar");
});

test("updating the store updates the value", async () => {
const input: HTMLInputElement = screen.getByLabelText(label);
expect(input.value).toBe("foo");

store.change((doc) => {
doc.data.value = "foo bar";
});

expect(input.value).toBe("foo bar");
});
});
});
89 changes: 89 additions & 0 deletions tests/actions/entity-checked.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { beforeEach, describe, expect, test } from "vitest";
import { render, screen } from "@testing-library/svelte";
import ActionsComponent from "./setup/EntityActionsComponent.svelte";
import { AutomergeStore } from "@onsetsoftware/automerge-store";
import type { DocumentShape, Person } from "./setup/document.type";
import { AutomergeEntityStore, AutomergeSvelteStore } from "../../src";
import { next as A } from "@automerge/automerge";
import { document } from "./setup/document";
import { get, writable } from "svelte/store";

describe("bind entity checked", async () => {
let root: AutomergeStore<DocumentShape>;
let store: AutomergeSvelteStore<DocumentShape>;
let entityStore: AutomergeEntityStore<DocumentShape, Person>;
beforeEach(async () => {
root = new AutomergeStore<DocumentShape>("actions-store", A.from(document));

store = new AutomergeSvelteStore(root);
entityStore = new AutomergeEntityStore(store, (doc) => doc.people);
});

test("checkbox is unchecked when multiple, different entities are selected", async () => {
render(ActionsComponent, { props: { store: entityStore } });
const checkbox: HTMLInputElement = screen.getByLabelText("checked");
expect(checkbox).not.toBeChecked();
});

test("checkbox is indeterminate when multiple, different entities are selected", async () => {
render(ActionsComponent, { props: { store: entityStore } });
const checkbox: HTMLInputElement = screen.getByLabelText("checked");
expect(checkbox.indeterminate).toBe(true);
});

test("checkbox is checked when a single true entity is selected", async () => {
render(ActionsComponent, {
props: { store: entityStore, ids: writable(["1"]) },
});
const checkbox: HTMLInputElement = screen.getByLabelText("checked");
expect(checkbox).toBeChecked();
});

test("checkbox is unchecked when a single false entity is selected", async () => {
render(ActionsComponent, {
props: { store: entityStore, ids: writable(["2"]) },
});
const checkbox: HTMLInputElement = screen.getByLabelText("checked");
expect(checkbox).not.toBeChecked();
});

test("checkbox is checked when multiple true entities are selected", async () => {
render(ActionsComponent, {
props: { store: entityStore, ids: writable(["1", "3"]) },
});
const checkbox: HTMLInputElement = screen.getByLabelText("checked");
expect(checkbox).toBeChecked();
});

test("updating a checkbox updates the store", async () => {
const ids = writable(["1", "2"]);
render(ActionsComponent, { props: { ids, store: entityStore } });
const checkbox: HTMLInputElement = screen.getByLabelText("checked");
expect(checkbox).not.toBeChecked();

expect(entityStore.get()?.entities[1].loggedIn).toBe(true);
expect(entityStore.get()?.entities[2].loggedIn).toBe(false);

checkbox.click();
expect(checkbox).toBeChecked();

get(ids).forEach((id) => {
expect(entityStore.get()?.entities[id].loggedIn).toBe(true);
});
});

test("updating the store updates the checkbox", async () => {
render(ActionsComponent, { props: { store: entityStore } });

const checkbox: HTMLInputElement = screen.getByLabelText("checked");
expect(checkbox).not.toBeChecked();

entityStore.update({
id: "2",
loggedIn: true,
});

expect(checkbox).toBeChecked();
expect(checkbox.indeterminate).toBe(false);
});
});
Loading

0 comments on commit 33188b8

Please sign in to comment.