Skip to content

Commit

Permalink
[Maintenance] improve testing utils and add delete-user-file test (ac…
Browse files Browse the repository at this point in the history
…tualbudget#421)

* improve testing utils and add delete-user-file test

* remove linting errors

* add release notes

* match npm scripts naming style

Co-authored-by: Matt Fiddaman <[email protected]>

* add raw middleware for /sync

---------

Co-authored-by: Matt Fiddaman <[email protected]>
  • Loading branch information
2 people authored and MMichotte committed Sep 9, 2024
1 parent 5e1889c commit d1213bc
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 4 deletions.
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
"lint": "eslint . --max-warnings 0",
"build": "tsc",
"test": "NODE_ENV=test NODE_OPTIONS='--experimental-vm-modules --trace-warnings' jest --coverage",
"db:migrate": "NODE_ENV=development node src/run-migrations.js up",
"db:downgrade": "NODE_ENV=development node src/run-migrations.js down",
"db:test-migrate": "NODE_ENV=test node src/run-migrations.js up",
"db:test-downgrade": "NODE_ENV=test node src/run-migrations.js down",
"types": "tsc --noEmit --incremental",
"verify": "yarn lint && yarn types",
"reset-password": "node src/scripts/reset-password.js",
Expand Down
27 changes: 23 additions & 4 deletions src/app-sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,13 @@ import { SyncProtoBuf } from '@actual-app/crdt';

const app = express();
app.use(errorMiddleware);
app.use(express.json());
app.use(express.raw({ type: 'application/actual-sync' }));

export { app as handlers };

const OK_RESPONSE = { status: 'ok' };

// This is a version representing the internal format of sync
// messages. When this changes, all sync files need to be reset. We
// will check this version when syncing and notify the user if they
Expand Down Expand Up @@ -160,7 +165,7 @@ app.post('/user-create-key', (req, res) => {
[keySalt, keyId, testContent, fileId],
);

res.send(JSON.stringify({ status: 'ok' }));
res.send(OK_RESPONSE);
});

app.post('/reset-user-file', async (req, res) => {
Expand Down Expand Up @@ -190,7 +195,7 @@ app.post('/reset-user-file', async (req, res) => {
}
}

res.send(JSON.stringify({ status: 'ok' }));
res.send(OK_RESPONSE);
});

app.post('/upload-user-file', async (req, res) => {
Expand Down Expand Up @@ -333,7 +338,7 @@ app.post('/update-user-filename', (req, res) => {

accountDb.mutate('UPDATE files SET name = ? WHERE id = ?', [name, fileId]);

res.send(JSON.stringify({ status: 'ok' }));
res.send(OK_RESPONSE);
});

app.get('/list-user-files', (req, res) => {
Expand Down Expand Up @@ -399,6 +404,20 @@ app.post('/delete-user-file', (req, res) => {
let accountDb = getAccountDb();
let { fileId } = req.body;

if (!fileId) {
return res.status(422).send({
details: 'fileId-required',
reason: 'unprocessable-entity',
status: 'error',
});
}

let rows = accountDb.all('SELECT * FROM files WHERE id = ?', [fileId]);

if (rows.length === 0) {
return res.status(400).send('file-not-found');
}

accountDb.mutate('UPDATE files SET deleted = TRUE WHERE id = ?', [fileId]);
res.send(JSON.stringify({ status: 'ok' }));
res.send(OK_RESPONSE);
});
62 changes: 62 additions & 0 deletions src/app-sync.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,65 @@ describe('/download-user-file', () => {
});
});
});

describe('/delete-user-file', () => {
it('returns 401 if the user is not authenticated', async () => {
const res = await request(app).post('/delete-user-file');

expect(res.statusCode).toEqual(401);
expect(res.body).toEqual({
details: 'token-not-found',
reason: 'unauthorized',
status: 'error',
});
});

// it returns 422 if the fileId is not provided
it('returns 422 if the fileId is not provided', async () => {
const res = await request(app)
.post('/delete-user-file')
.set('x-actual-token', 'valid-token');

expect(res.statusCode).toEqual(422);
expect(res.body).toEqual({
details: 'fileId-required',
reason: 'unprocessable-entity',
status: 'error',
});
});

it('returns 400 if the file does not exist', async () => {
const res = await request(app)
.post('/delete-user-file')
.set('x-actual-token', 'valid-token')
.send({ fileId: 'non-existing-file-id' });

expect(res.statusCode).toEqual(400);
expect(res.text).toEqual('file-not-found');
});

it('marks the file as deleted', async () => {
const accountDb = getAccountDb();
const fileId = 'existing-file-id';

// Insert a file into the database
accountDb.mutate(
'INSERT OR IGNORE INTO files (id, deleted) VALUES (?, FALSE)',
[fileId],
);

const res = await request(app)
.post('/delete-user-file')
.set('x-actual-token', 'valid-token')
.send({ fileId });

expect(res.statusCode).toEqual(200);
expect(res.body).toEqual({ status: 'ok' });

// Verify that the file is marked as deleted
const rows = accountDb.all('SELECT deleted FROM files WHERE id = ?', [
fileId,
]);
expect(rows[0].deleted).toBe(1);
});
});
8 changes: 8 additions & 0 deletions src/run-migrations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import run from './migrations.js';

const direction = process.argv[2] || 'up';

run(direction).catch((err) => {
console.error('Migration failed:', err);
process.exit(1);
});
6 changes: 6 additions & 0 deletions upcoming-release-notes/421.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
category: Maintenance
authors: [tcrasset]
---

Improve testing utils and add delete-user-file test

0 comments on commit d1213bc

Please sign in to comment.