mirror of
https://github.com/actualbudget/actual.git
synced 2026-03-11 20:44:32 -05:00
✅ (adding jest for unit/integration tests) (#91)
This commit is contained in:
committed by
GitHub
parent
9fc9d5c642
commit
f0772b147f
@@ -3,7 +3,8 @@ module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
amd: true,
|
||||
node: true
|
||||
node: true,
|
||||
jest: true
|
||||
},
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['@typescript-eslint', 'prettier'],
|
||||
|
||||
29
.github/workflows/test.yml
vendored
Normal file
29
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
name: Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches: '*'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 16
|
||||
- name: Cache
|
||||
uses: actions/cache@v2
|
||||
id: cache
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
key: yarn-v1-${{ hashFiles('**/yarn.lock') }}
|
||||
- name: Install
|
||||
run: yarn --immutable
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
- name: Test
|
||||
run: yarn test
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,6 +7,8 @@ supervise
|
||||
bin/large-sync-data.txt
|
||||
user-files
|
||||
server-files
|
||||
test-user-files
|
||||
test-server-files
|
||||
fly.toml
|
||||
build/
|
||||
|
||||
|
||||
77
app-sync.test.js
Normal file
77
app-sync.test.js
Normal file
@@ -0,0 +1,77 @@
|
||||
const fs = require('fs');
|
||||
const request = require('supertest');
|
||||
const { handlers: app } = require('./app-sync');
|
||||
const { getAccountDb } = require('./account-db');
|
||||
const { getPathForUserFile } = require('./util/paths');
|
||||
|
||||
describe('/download-user-file', () => {
|
||||
describe('default version', () => {
|
||||
it('returns 401 if the user is not authenticated', async () => {
|
||||
const res = await request(app).get('/download-user-file');
|
||||
|
||||
expect(res.statusCode).toEqual(401);
|
||||
expect(res.body).toEqual({
|
||||
details: 'token-not-found',
|
||||
reason: 'unauthorized',
|
||||
status: 'error'
|
||||
});
|
||||
});
|
||||
|
||||
it('returns 401 if the user is invalid', async () => {
|
||||
const res = await request(app)
|
||||
.get('/download-user-file')
|
||||
.set('x-actual-token', 'invalid-token');
|
||||
|
||||
expect(res.statusCode).toEqual(401);
|
||||
expect(res.body).toEqual({
|
||||
details: 'token-not-found',
|
||||
reason: 'unauthorized',
|
||||
status: 'error'
|
||||
});
|
||||
});
|
||||
|
||||
it('returns 400 error if the file does not exist in the database', async () => {
|
||||
const res = await request(app)
|
||||
.get('/download-user-file')
|
||||
.set('x-actual-token', 'valid-token')
|
||||
.set('x-actual-file-id', 'non-existing-file-id');
|
||||
|
||||
expect(res.statusCode).toEqual(400);
|
||||
});
|
||||
|
||||
it('returns 500 error if the file does not exist on the filesystem', async () => {
|
||||
getAccountDb().mutate(
|
||||
'INSERT INTO files (id, deleted) VALUES (?, FALSE)',
|
||||
['missing-fs-file']
|
||||
);
|
||||
|
||||
const res = await request(app)
|
||||
.get('/download-user-file')
|
||||
.set('x-actual-token', 'valid-token')
|
||||
.set('x-actual-file-id', 'missing-fs-file');
|
||||
|
||||
expect(res.statusCode).toEqual(500);
|
||||
});
|
||||
|
||||
it('returns an attachment file', async () => {
|
||||
fs.writeFileSync(getPathForUserFile('file-id'), 'content');
|
||||
getAccountDb().mutate(
|
||||
'INSERT INTO files (id, deleted) VALUES (?, FALSE)',
|
||||
['file-id']
|
||||
);
|
||||
|
||||
const res = await request(app)
|
||||
.get('/download-user-file')
|
||||
.set('x-actual-token', 'valid-token')
|
||||
.set('x-actual-file-id', 'file-id');
|
||||
|
||||
expect(res.statusCode).toEqual(200);
|
||||
expect(res.headers).toEqual(
|
||||
expect.objectContaining({
|
||||
'content-disposition': 'attachment;filename=file-id',
|
||||
'content-type': 'application/octet-stream'
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
4
jest.config.json
Normal file
4
jest.config.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"setupFiles": ["./jest.setup.js"],
|
||||
"testPathIgnorePatterns": ["/node_modules/", "/build/"]
|
||||
}
|
||||
17
jest.setup.js
Normal file
17
jest.setup.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const fs = require('fs');
|
||||
const { join } = require('path');
|
||||
const { getAccountDb } = require('./account-db');
|
||||
const config = require('./load-config');
|
||||
|
||||
// Delete previous test database (force creation of a new one)
|
||||
const dbPath = join(config.serverFiles, 'account.sqlite');
|
||||
if (fs.existsSync(dbPath)) fs.unlinkSync(dbPath);
|
||||
|
||||
// Create path for test user files and delete previous files there
|
||||
if (fs.existsSync(config.userFiles))
|
||||
fs.rmdirSync(config.userFiles, { recursive: true });
|
||||
fs.mkdirSync(config.userFiles);
|
||||
|
||||
// Insert a fake "valid-token" fixture that can be reused
|
||||
const db = getAccountDb();
|
||||
db.mutate('INSERT INTO sessions (token) VALUES (?)', ['valid-token']);
|
||||
@@ -7,13 +7,23 @@ try {
|
||||
let { join } = require('path');
|
||||
let root = fs.existsSync('/data') ? '/data' : __dirname;
|
||||
|
||||
config = {
|
||||
mode: 'development',
|
||||
port: 5006,
|
||||
hostname: '0.0.0.0',
|
||||
serverFiles: join(root, 'server-files'),
|
||||
userFiles: join(root, 'user-files')
|
||||
};
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
config = {
|
||||
mode: 'test',
|
||||
port: 5006,
|
||||
hostname: '0.0.0.0',
|
||||
serverFiles: join(__dirname, 'test-server-files'),
|
||||
userFiles: join(__dirname, 'test-user-files')
|
||||
};
|
||||
} else {
|
||||
config = {
|
||||
mode: 'development',
|
||||
port: 5006,
|
||||
hostname: '0.0.0.0',
|
||||
serverFiles: join(root, 'server-files'),
|
||||
userFiles: join(root, 'user-files')
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// The env variable always takes precedence
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"start": "node app",
|
||||
"lint": "eslint .",
|
||||
"build": "tsc",
|
||||
"test": "jest",
|
||||
"types": "tsc --noEmit --incremental",
|
||||
"verify": "yarn -s lint && yarn types"
|
||||
},
|
||||
@@ -26,12 +27,16 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/better-sqlite3": "^7.5.0",
|
||||
"@types/jest": "^29.2.3",
|
||||
"@types/node": "^17.0.31",
|
||||
"@types/supertest": "^2.0.12",
|
||||
"@typescript-eslint/eslint-plugin": "^5.23.0",
|
||||
"@typescript-eslint/parser": "^5.23.0",
|
||||
"eslint": "^8.15.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jest": "^29.3.1",
|
||||
"prettier": "^2.6.2",
|
||||
"supertest": "^6.3.1",
|
||||
"typescript": "^4.6.4"
|
||||
},
|
||||
"packageManager": "yarn@3.2.1"
|
||||
|
||||
Reference in New Issue
Block a user