@stanlemon/app-template 0.2.10 → 0.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/app.js CHANGED
@@ -3,19 +3,19 @@ import {
3
3
  asyncJsonHandler as handler,
4
4
  SimpleUsersDao,
5
5
  } from "@stanlemon/server-with-auth";
6
- import { Low, JSONFile } from "lowdb";
7
-
8
- const adapter = new JSONFile("./db.json");
9
6
 
7
+ const dao = new SimpleUsersDao();
10
8
  const app = createAppServer({
11
9
  webpack: "http://localhost:8080",
12
10
  secure: ["/api/"],
13
- ...new SimpleUsersDao([], adapter),
11
+ ...dao,
14
12
  });
15
13
 
16
- const db = new Low(adapter);
17
- await db.read();
18
- db.data.items ||= [];
14
+ export const db = dao.getDb();
15
+ db.read().then(() => {
16
+ if (!db.data) db.data = { items: [] };
17
+ db.data.items = db.data.items || [];
18
+ });
19
19
 
20
20
  app.get(
21
21
  "/api/items",
@@ -24,18 +24,20 @@ app.get(
24
24
 
25
25
  app.post(
26
26
  "/api/items",
27
- handler(async (item) => {
28
- db.data.items.push(item);
27
+ handler(async ({ item }) => {
28
+ db.data.items.push({ item, id: dao.generateId() });
29
29
  await db.write();
30
30
  return db.data.items;
31
31
  })
32
32
  );
33
33
 
34
34
  app.delete(
35
- "/api/items/:item",
36
- handler(async ({ item }) => {
37
- db.data.items = db.data.items.filter((i) => i !== item);
35
+ "/api/items/:id",
36
+ handler(async ({ id }) => {
37
+ db.data.items = db.data.items.filter((item) => id !== item.id);
38
38
  await db.write();
39
39
  return db.data.items;
40
40
  })
41
41
  );
42
+
43
+ export default app;
package/app.test.js ADDED
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @jest-environment node
3
+ */
4
+ import request from "supertest";
5
+ import app, { db } from "./app.js";
6
+
7
+ describe("/app", () => {
8
+ afterEach(() => {
9
+ // Prevent data from bleeding over after each test
10
+ db.data.items = [];
11
+ });
12
+
13
+ it("lists items", async () => {
14
+ const response = await request(app)
15
+ .get("/api/items")
16
+ .set("Accept", "application/json");
17
+
18
+ expect(response.headers["content-type"]).toMatch(/json/);
19
+ expect(response.status).toEqual(200);
20
+ expect(response.body).toEqual([]);
21
+ });
22
+
23
+ it("add item", async () => {
24
+ const response = await request(app)
25
+ .post("/api/items")
26
+ .set("Accept", "application/json")
27
+ .send({ item: "hello world" });
28
+
29
+ expect(response.headers["content-type"]).toMatch(/json/);
30
+ expect(response.status).toEqual(200);
31
+ expect(response.body).toMatchObject([{ item: "hello world" }]);
32
+ });
33
+
34
+ it("delete item", async () => {
35
+ const response1 = await request(app)
36
+ .post("/api/items")
37
+ .set("Accept", "application/json")
38
+ .send({ item: "hello world" });
39
+
40
+ const items = response1.body;
41
+
42
+ const response2 = await request(app)
43
+ .delete(`/api/items/${items[0].id}`)
44
+ .set("Accept", "application/json");
45
+
46
+ expect(response2.headers["content-type"]).toMatch(/json/);
47
+ expect(response2.status).toEqual(200);
48
+ expect(response2.body).toMatchObject([]);
49
+ });
50
+ });
package/jest.config.js CHANGED
@@ -1 +1 @@
1
- export { default } from "@stanlemon/webdev/jest.config.js";
1
+ export { default } from "@stanlemon/webdev/jest.config.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stanlemon/app-template",
3
- "version": "0.2.10",
3
+ "version": "0.2.14",
4
4
  "description": "A template for creating apps using the webdev package.",
5
5
  "author": "Stan Lemon <stanlemon@users.noreply.github.com>",
6
6
  "license": "MIT",
@@ -18,15 +18,16 @@
18
18
  "lint:format": "eslint --fix --ext js,jsx,ts,tsx ./src/"
19
19
  },
20
20
  "dependencies": {
21
- "@stanlemon/server-with-auth": "0.1.4",
21
+ "@stanlemon/server-with-auth": "*",
22
22
  "@stanlemon/webdev": "*",
23
23
  "react": "^18.1.0",
24
24
  "react-dom": "^18.1.0"
25
25
  },
26
26
  "devDependencies": {
27
- "@testing-library/react": "^13.1.1",
28
- "@testing-library/user-event": "^14.1.1",
29
- "@types/react": "^18.0.8",
30
- "@types/react-dom": "^18.0.3"
27
+ "@testing-library/react": "^13.2.0",
28
+ "@testing-library/user-event": "^14.2.0",
29
+ "@types/react": "^18.0.9",
30
+ "@types/react-dom": "^18.0.4",
31
+ "supertest": "^6.2.3"
31
32
  }
32
33
  }
package/src/App.test.tsx CHANGED
@@ -1,12 +1,15 @@
1
1
  import { render, screen, fireEvent, act } from "@testing-library/react";
2
2
  import userEvent from "@testing-library/user-event";
3
- import App from "./App";
3
+ import App, { ItemData } from "./App";
4
4
  import { SessionContext } from "./Session";
5
5
 
6
- const output = ["item one", "item two"];
6
+ const output = [
7
+ { id: "1", item: "item one" },
8
+ { id: "2", item: "item two" },
9
+ ];
7
10
  global.fetch = jest.fn((url, opts: { method: string; body: string }) => {
8
11
  if (opts.method === "post") {
9
- output.push(JSON.parse(opts.body) as string);
12
+ output.push(JSON.parse(opts.body) as ItemData);
10
13
  }
11
14
  return Promise.resolve({
12
15
  ok: true,
package/src/App.tsx CHANGED
@@ -1,4 +1,5 @@
1
1
  import React, { useState, useContext, useEffect } from "react";
2
+
2
3
  import "./App.less";
3
4
  import { SessionContext } from "./Session";
4
5
  import Header from "./Header";
@@ -14,9 +15,15 @@ export type FormErrors = {
14
15
  errors: Record<string, string>;
15
16
  };
16
17
 
18
+ export type ItemData = {
19
+ id: string;
20
+ item: string;
21
+ };
22
+
23
+ // eslint-disable-next-line max-lines-per-function
17
24
  export default function App() {
18
25
  const [loaded, setLoaded] = useState<boolean>(false);
19
- const [items, setItems] = useState<string[]>([]);
26
+ const [items, setItems] = useState<ItemData[]>([]);
20
27
  const [error, setError] = useState<string | boolean>(false);
21
28
 
22
29
  const { session, setSession } = useContext(SessionContext);
@@ -33,7 +40,7 @@ export default function App() {
33
40
  return;
34
41
  }
35
42
 
36
- fetchApi<string[], null>("/api/items", session?.token || "")
43
+ fetchApi<ItemData[], null>("/api/items", session?.token || "")
37
44
  .then((items) => {
38
45
  setLoaded(true);
39
46
  setItems(items);
@@ -42,16 +49,23 @@ export default function App() {
42
49
  });
43
50
 
44
51
  const saveItem = (item: string) => {
45
- fetchApi<string[], string>("/api/items", session?.token || "", "post", item)
52
+ fetchApi<ItemData[], { item: string }>(
53
+ "/api/items",
54
+ session?.token || "",
55
+ "post",
56
+ {
57
+ item,
58
+ }
59
+ )
46
60
  .then((items) => {
47
61
  setItems(items);
48
62
  })
49
63
  .catch(catchError);
50
64
  };
51
65
 
52
- const deleteItem = (item: string) => {
53
- fetchApi<string[], string>(
54
- "/api/items/" + item,
66
+ const deleteItem = (id: string) => {
67
+ fetchApi<ItemData[], string>(
68
+ `/api/items/${id}`,
55
69
  session?.token || "",
56
70
  "delete"
57
71
  )
@@ -103,7 +117,7 @@ function ItemList({
103
117
  saveItem,
104
118
  deleteItem,
105
119
  }: {
106
- items: string[];
120
+ items: ItemData[];
107
121
  saveItem(item: string): void;
108
122
  deleteItem(item: string): void;
109
123
  }) {
@@ -128,11 +142,11 @@ function ItemList({
128
142
  <Spacer />
129
143
  <h2>My Items</h2>
130
144
  <ul style={{ padding: 0 }}>
131
- {items.map((item, i) => (
145
+ {items.map(({ item, id }, i) => (
132
146
  <Row key={i} as="li">
133
147
  <button
134
148
  style={{ marginLeft: "auto", order: 2 }}
135
- onClick={() => deleteItem(item)}
149
+ onClick={() => deleteItem(id)}
136
150
  >
137
151
  Delete
138
152
  </button>