@jsnote-zeina/local-api 1.0.3 → 1.0.5
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/dist/routes/cells.test.d.ts +1 -0
- package/dist/routes/cells.test.js +108 -0
- package/package.json +14 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const express_1 = __importDefault(require("express"));
|
|
16
|
+
const supertest_1 = __importDefault(require("supertest"));
|
|
17
|
+
const fs_1 = require("fs");
|
|
18
|
+
const os_1 = __importDefault(require("os"));
|
|
19
|
+
const path_1 = __importDefault(require("path"));
|
|
20
|
+
const vitest_1 = require("vitest");
|
|
21
|
+
const cells_1 = require("./cells");
|
|
22
|
+
(0, vitest_1.describe)('cells router', () => {
|
|
23
|
+
let tmpDir;
|
|
24
|
+
let app;
|
|
25
|
+
const filename = 'notebook.js';
|
|
26
|
+
const filepath = () => path_1.default.join(tmpDir, filename);
|
|
27
|
+
(0, vitest_1.beforeEach)(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
28
|
+
tmpDir = yield fs_1.promises.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'jbook-cells-test-'));
|
|
29
|
+
app = (0, express_1.default)();
|
|
30
|
+
app.use((0, cells_1.createCellsRouter)(filename, tmpDir));
|
|
31
|
+
}));
|
|
32
|
+
(0, vitest_1.afterEach)(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
33
|
+
yield fs_1.promises.rm(tmpDir, { recursive: true, force: true });
|
|
34
|
+
}));
|
|
35
|
+
(0, vitest_1.describe)('GET /cells', () => {
|
|
36
|
+
(0, vitest_1.it)('returns 3 default cells and seeds the file when missing', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
37
|
+
const res = yield (0, supertest_1.default)(app).get('/cells');
|
|
38
|
+
(0, vitest_1.expect)(res.status).toBe(200);
|
|
39
|
+
(0, vitest_1.expect)(res.body).toHaveLength(3);
|
|
40
|
+
// file was seeded with the same defaults
|
|
41
|
+
const onDisk = JSON.parse(yield fs_1.promises.readFile(filepath(), 'utf-8'));
|
|
42
|
+
(0, vitest_1.expect)(onDisk).toEqual(res.body);
|
|
43
|
+
}));
|
|
44
|
+
(0, vitest_1.it)('returns the file content when shape is valid', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
45
|
+
const cells = [
|
|
46
|
+
{ id: 'a', type: 'text', content: 'hello' },
|
|
47
|
+
{ id: 'b', type: 'code', content: 'const x = 1;' },
|
|
48
|
+
];
|
|
49
|
+
yield fs_1.promises.writeFile(filepath(), JSON.stringify(cells));
|
|
50
|
+
const res = yield (0, supertest_1.default)(app).get('/cells');
|
|
51
|
+
(0, vitest_1.expect)(res.status).toBe(200);
|
|
52
|
+
(0, vitest_1.expect)(res.body).toEqual(cells);
|
|
53
|
+
}));
|
|
54
|
+
(0, vitest_1.it)('serves defaults (does not crash) when the file is invalid JSON', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
55
|
+
yield fs_1.promises.writeFile(filepath(), 'this is { not json');
|
|
56
|
+
const res = yield (0, supertest_1.default)(app).get('/cells');
|
|
57
|
+
(0, vitest_1.expect)(res.status).toBe(200);
|
|
58
|
+
(0, vitest_1.expect)(res.body).toHaveLength(3);
|
|
59
|
+
// file is NOT overwritten — user's broken content is preserved
|
|
60
|
+
const onDisk = yield fs_1.promises.readFile(filepath(), 'utf-8');
|
|
61
|
+
(0, vitest_1.expect)(onDisk).toBe('this is { not json');
|
|
62
|
+
}));
|
|
63
|
+
(0, vitest_1.it)('serves defaults when the file is JSON but not an array', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
64
|
+
yield fs_1.promises.writeFile(filepath(), JSON.stringify({ not: 'an array' }));
|
|
65
|
+
const res = yield (0, supertest_1.default)(app).get('/cells');
|
|
66
|
+
(0, vitest_1.expect)(res.status).toBe(200);
|
|
67
|
+
(0, vitest_1.expect)(res.body).toHaveLength(3);
|
|
68
|
+
}));
|
|
69
|
+
(0, vitest_1.it)('serves defaults when the array contains malformed cells', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
70
|
+
yield fs_1.promises.writeFile(filepath(), JSON.stringify([{ foo: 'bar' }, { id: 42, type: 'code', content: 'x' }]));
|
|
71
|
+
const res = yield (0, supertest_1.default)(app).get('/cells');
|
|
72
|
+
(0, vitest_1.expect)(res.status).toBe(200);
|
|
73
|
+
(0, vitest_1.expect)(res.body).toHaveLength(3);
|
|
74
|
+
}));
|
|
75
|
+
(0, vitest_1.it)('accepts an empty array as valid', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
76
|
+
yield fs_1.promises.writeFile(filepath(), '[]');
|
|
77
|
+
const res = yield (0, supertest_1.default)(app).get('/cells');
|
|
78
|
+
(0, vitest_1.expect)(res.status).toBe(200);
|
|
79
|
+
(0, vitest_1.expect)(res.body).toEqual([]);
|
|
80
|
+
}));
|
|
81
|
+
(0, vitest_1.it)('rejects a cell with type other than "code" or "text"', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
82
|
+
yield fs_1.promises.writeFile(filepath(), JSON.stringify([{ id: 'a', type: 'markdown', content: 'x' }]));
|
|
83
|
+
const res = yield (0, supertest_1.default)(app).get('/cells');
|
|
84
|
+
(0, vitest_1.expect)(res.body).toHaveLength(3); // defaults
|
|
85
|
+
}));
|
|
86
|
+
});
|
|
87
|
+
(0, vitest_1.describe)('POST /cells', () => {
|
|
88
|
+
(0, vitest_1.it)('round-trips the cells payload', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
89
|
+
const cells = [
|
|
90
|
+
{ id: 'x', type: 'code', content: 'const x = 1;' },
|
|
91
|
+
{ id: 'y', type: 'text', content: '# heading' },
|
|
92
|
+
];
|
|
93
|
+
const post = yield (0, supertest_1.default)(app).post('/cells').send({ cells });
|
|
94
|
+
(0, vitest_1.expect)(post.status).toBe(200);
|
|
95
|
+
(0, vitest_1.expect)(post.body).toEqual({ status: 'ok' });
|
|
96
|
+
const get = yield (0, supertest_1.default)(app).get('/cells');
|
|
97
|
+
(0, vitest_1.expect)(get.body).toEqual(cells);
|
|
98
|
+
}));
|
|
99
|
+
(0, vitest_1.it)('overwrites existing content on POST', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
100
|
+
const original = [{ id: 'a', type: 'text', content: 'first' }];
|
|
101
|
+
const replacement = [{ id: 'b', type: 'code', content: 'second' }];
|
|
102
|
+
yield fs_1.promises.writeFile(filepath(), JSON.stringify(original));
|
|
103
|
+
yield (0, supertest_1.default)(app).post('/cells').send({ cells: replacement });
|
|
104
|
+
const onDisk = JSON.parse(yield fs_1.promises.readFile(filepath(), 'utf-8'));
|
|
105
|
+
(0, vitest_1.expect)(onDisk).toEqual(replacement);
|
|
106
|
+
}));
|
|
107
|
+
});
|
|
108
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsnote-zeina/local-api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
"types": "dist/index.d.ts",
|
|
13
13
|
"scripts": {
|
|
14
14
|
"start": "tsc --watch --preserveWatchOutput",
|
|
15
|
-
"
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"test:watch": "vitest",
|
|
18
|
+
"prepublishOnly": "npm run build"
|
|
16
19
|
},
|
|
17
20
|
"keywords": [],
|
|
18
21
|
"author": "",
|
|
@@ -20,12 +23,18 @@
|
|
|
20
23
|
"devDependencies": {
|
|
21
24
|
"@types/cors": "^2.8.17",
|
|
22
25
|
"@types/express": "^4.17.21",
|
|
23
|
-
"
|
|
26
|
+
"@types/http-proxy": "^1.17.15",
|
|
27
|
+
"@types/supertest": "^6.0.2",
|
|
28
|
+
"supertest": "^7.0.0",
|
|
29
|
+
"typescript": "^5.4.5",
|
|
30
|
+
"vitest": "^1.6.0"
|
|
24
31
|
},
|
|
25
32
|
"dependencies": {
|
|
26
|
-
"@jsnote-zeina/local-client": "^1.0.
|
|
33
|
+
"@jsnote-zeina/local-client": "^1.0.5",
|
|
27
34
|
"cors": "^2.8.5",
|
|
28
35
|
"express": "^4.19.2",
|
|
29
|
-
"http-proxy
|
|
36
|
+
"http-proxy": "^1.18.1",
|
|
37
|
+
"http-proxy-middleware": "^3.0.0",
|
|
38
|
+
"is-glob": "^4.0.3"
|
|
30
39
|
}
|
|
31
40
|
}
|