@stanlemon/app-template 0.2.10 → 0.2.12
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 +11 -12
- package/app.test.js +50 -0
- package/jest.config.js +1 -1
- package/package.json +4 -3
- package/src/App.test.tsx +6 -3
- package/src/App.tsx +23 -9
package/app.js
CHANGED
|
@@ -3,19 +3,16 @@ 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
|
-
...
|
|
11
|
+
...dao,
|
|
14
12
|
});
|
|
15
13
|
|
|
16
|
-
const db =
|
|
17
|
-
|
|
18
|
-
db.data.items ||= [];
|
|
14
|
+
export const db = dao.getDb();
|
|
15
|
+
db.read().then(() => (db.data.items = db.data.items || []));
|
|
19
16
|
|
|
20
17
|
app.get(
|
|
21
18
|
"/api/items",
|
|
@@ -24,18 +21,20 @@ app.get(
|
|
|
24
21
|
|
|
25
22
|
app.post(
|
|
26
23
|
"/api/items",
|
|
27
|
-
handler(async (item) => {
|
|
28
|
-
db.data.items.push(item);
|
|
24
|
+
handler(async ({ item }) => {
|
|
25
|
+
db.data.items.push({ item, id: dao.generateId() });
|
|
29
26
|
await db.write();
|
|
30
27
|
return db.data.items;
|
|
31
28
|
})
|
|
32
29
|
);
|
|
33
30
|
|
|
34
31
|
app.delete(
|
|
35
|
-
"/api/items/:
|
|
36
|
-
handler(async ({
|
|
37
|
-
db.data.items = db.data.items.filter((
|
|
32
|
+
"/api/items/:id",
|
|
33
|
+
handler(async ({ id }) => {
|
|
34
|
+
db.data.items = db.data.items.filter((item) => id !== item.id);
|
|
38
35
|
await db.write();
|
|
39
36
|
return db.data.items;
|
|
40
37
|
})
|
|
41
38
|
);
|
|
39
|
+
|
|
40
|
+
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.
|
|
3
|
+
"version": "0.2.12",
|
|
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,7 +18,7 @@
|
|
|
18
18
|
"lint:format": "eslint --fix --ext js,jsx,ts,tsx ./src/"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@stanlemon/server-with-auth": "
|
|
21
|
+
"@stanlemon/server-with-auth": "*",
|
|
22
22
|
"@stanlemon/webdev": "*",
|
|
23
23
|
"react": "^18.1.0",
|
|
24
24
|
"react-dom": "^18.1.0"
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"@testing-library/react": "^13.1.1",
|
|
28
28
|
"@testing-library/user-event": "^14.1.1",
|
|
29
29
|
"@types/react": "^18.0.8",
|
|
30
|
-
"@types/react-dom": "^18.0.3"
|
|
30
|
+
"@types/react-dom": "^18.0.3",
|
|
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 = [
|
|
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
|
|
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<
|
|
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<
|
|
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<
|
|
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 = (
|
|
53
|
-
fetchApi<
|
|
54
|
-
|
|
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:
|
|
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(
|
|
149
|
+
onClick={() => deleteItem(id)}
|
|
136
150
|
>
|
|
137
151
|
Delete
|
|
138
152
|
</button>
|