2
0
mirror of https://github.com/frappe/books.git synced 2024-11-08 23:00:56 +00:00

a better way to test REST API

This commit is contained in:
Rushabh Mehta 2018-01-03 12:19:59 +05:30
parent 98d8077282
commit 634fa80d10
15 changed files with 110 additions and 47 deletions

View File

@ -43,10 +43,11 @@ Models are declared by adding a `.json` model file in the `models/doctype` folde
```js ```js
const frappe = require('frappe-core'); const frappe = require('frappe-core');
frappe.init(); await frappe.init();
await frappe.init_db('sqlite', {db_path: 'test.db'});
// sync all schema from `models` folders in all apps // sync all schema from `models` folders in all apps
frappe.migrate(); await frappe.migrate();
``` ```
## Managing Documents ## Managing Documents
@ -64,6 +65,7 @@ Documents are initialized with the `frappe.get_doc` method. If `doctype` and `na
```js ```js
const frappe = require('frappe-core'); const frappe = require('frappe-core');
await frappe.init(); await frappe.init();
await frappe.init_db('sqlite', {db_path: 'test.db'});
// make a new todo // make a new todo
let todo = await frappe.get_doc({doctype: 'ToDo', subject: 'something'}); let todo = await frappe.get_doc({doctype: 'ToDo', subject: 'something'});
@ -76,6 +78,7 @@ You can insert a document in the backend with the `insert` method.
```js ```js
const frappe = require('frappe-core'); const frappe = require('frappe-core');
await frappe.init(); await frappe.init();
await frappe.init_db('sqlite', {db_path: 'test.db'});
// make a new todo // make a new todo
let todo = await frappe.get_doc({doctype: 'ToDo', subject: 'something'}); let todo = await frappe.get_doc({doctype: 'ToDo', subject: 'something'});
@ -89,6 +92,7 @@ You can read a document from the backend with the `frappe.get_doc` method
```js ```js
const frappe = require('frappe-core'); const frappe = require('frappe-core');
await frappe.init(); await frappe.init();
await frappe.init_db('sqlite', {db_path: 'test.db'});
// get all open todos // get all open todos
let todos = await frappe.db.get_all('ToDo', ['name'], {status: "Open"}); let todos = await frappe.db.get_all('ToDo', ['name'], {status: "Open"});
@ -102,6 +106,7 @@ The `update` method updates a document.
```js ```js
const frappe = require('frappe-core'); const frappe = require('frappe-core');
await frappe.init(); await frappe.init();
await frappe.init_db('sqlite', {db_path: 'test.db'});
// get all open todos // get all open todos
let todos = await frappe.db.get_all('ToDo', ['name'], {status: "Open"}); let todos = await frappe.db.get_all('ToDo', ['name'], {status: "Open"});
@ -118,6 +123,7 @@ The `delete` method deletes a document.
```js ```js
const frappe = require('frappe-core'); const frappe = require('frappe-core');
await frappe.init(); await frappe.init();
await frappe.init_db('sqlite', {db_path: 'test.db'});
// get all open todos // get all open todos
let todos = await frappe.db.get_all('ToDo', ['name'], {status: "Open"}); let todos = await frappe.db.get_all('ToDo', ['name'], {status: "Open"});
@ -132,7 +138,8 @@ Metadata are first class objects in Frappe. You can get a metadata object by `fr
```js ```js
const frappe = require('frappe-core'); const frappe = require('frappe-core');
frappe.init(); await frappe.init();
await frappe.init_db('sqlite', {db_path: 'test.db'});
let todo_meta = frappe.get_meta('ToDo'); let todo_meta = frappe.get_meta('ToDo');
@ -189,7 +196,8 @@ You can also directly write SQL with `frappe.db.sql`
```js ```js
const frappe = require('frappe-core'); const frappe = require('frappe-core');
frappe.init(); await frappe.init();
await frappe.init_db('sqlite', {db_path: 'test.db'});
all_todos = frappe.db.sql('select name from todo'); all_todos = frappe.db.sql('select name from todo');
``` ```

View File

@ -1,6 +1,11 @@
const app = require('express')(); const app = require('express')();
const frappe = require('frappe-core'); const frappe = require('frappe-core');
// setup frappe REST routes async function start() {
frappe.init({app:app}).then(frappe.start()); await frappe.init();
await frappe.init_db('sqlite', {db_path: 'test.db'});
await frappe.init_app(app);
await frappe.start();
}
start();

View File

@ -1,18 +1,18 @@
const frappe = require('frappe-core'); const frappe = require('frappe-core');
const sqlite3 = require('sqlite3').verbose(); const sqlite3 = require('sqlite3').verbose();
class SQLLiteDatabase { class sqliteDatabase {
constructor(db_name) { constructor({db_path}) {
this.conn_name = db_name; this.db_path = db_path;
this.init_type_map(); this.init_type_map();
} }
connect(db_name) { connect(db_path) {
if (db_name) { if (db_path) {
this.conn_name = db_name; this.db_path = db_path;
} }
return new Promise(resolve => { return new Promise(resolve => {
this.conn = new sqlite3.Database(this.conn_name, () => { this.conn = new sqlite3.Database(this.db_path, () => {
resolve(); resolve();
}); });
}); });
@ -211,4 +211,4 @@ class SQLLiteDatabase {
} }
module.exports = { Database: SQLLiteDatabase }; module.exports = { Database: sqliteDatabase };

View File

@ -2,21 +2,21 @@ const path = require('path');
const bodyParser = require('body-parser'); const bodyParser = require('body-parser');
module.exports = { module.exports = {
async init({db_name ='test.db', user, user_key, for_test} = {}) { async init() {
this.db_name = db_name;
if (this._initialized) return; if (this._initialized) return;
this.init_config(); this.init_config();
this.init_errors(); this.init_errors();
this.init_globals(); this.init_globals();
this.init_libs(); this.init_libs();
await this.init_db();
this._initialized = true; this._initialized = true;
this.login(user, user_key);
// login as guest
this.login();
}, },
init_config() { init_config() {
this.config = { this.config = {
backend: 'sqllite' backend: 'sqlite'
}; };
}, },
@ -56,10 +56,20 @@ module.exports = {
this.server = this.app.listen(port); this.server = this.app.listen(port);
}, },
async init_db() { async init_db(db_type, options) {
let database = require('./backends/' + this.config.backend); var Database;
this.db = new database.Database(this.db_name); switch (db_type) {
await this.db.connect(this.db_name); case 'sqlite':
Database = require('./backends/sqlite').Database;
break;
case 'rest':
Database = require('./backends/rest_client').Database;
break;
default:
throw new Error(`${db_type} is not a supported database type`);
}
this.db = new Database(options);
await this.db.connect();
}, },
get_meta(doctype) { get_meta(doctype) {
@ -86,7 +96,7 @@ module.exports = {
return await doc.insert(); return await doc.insert();
}, },
login(user, user_key) { login(user='guest', user_key) {
this.session = new this.session_lib.Session(user); this.session = new this.session_lib.Session(user);
if (user && user_key) { if (user && user_key) {
this.login(user_key); this.login(user_key);
@ -95,6 +105,9 @@ module.exports = {
close() { close() {
this.db.close(); this.db.close();
this.server.close();
if (this.server) {
this.server.close();
}
} }
}; };

View File

@ -19,13 +19,13 @@ module.exports = {
return response.json(doc.get_valid_dict()); return response.json(doc.get_valid_dict());
}); });
// get list // get document
app.get('/api/resource/:doctype/:name', async function(request, response) { app.get('/api/resource/:doctype/:name', async function(request, response) {
let data = await frappe.get_doc(request.params.doctype, request.params.name).get_valid_dict(); let data = await frappe.get_doc(request.params.doctype, request.params.name).get_valid_dict();
return response.json(data); return response.json(data);
}); });
// get list // delete
app.delete('/api/resource/:doctype/:name', async function(request, response) { app.delete('/api/resource/:doctype/:name', async function(request, response) {
let data = await frappe.get_doc(request.params.doctype, request.params.name).delete(); let data = await frappe.get_doc(request.params.doctype, request.params.name).delete();
return response.json(data); return response.json(data);

9
frappe/tests/helpers.js Normal file
View File

@ -0,0 +1,9 @@
const frappe = require('frappe-core');
module.exports = {
async init_sqlite() {
await frappe.init();
await frappe.init_db('sqlite', {db_path: 'test.db'});
await frappe.db.migrate();
}
}

View File

@ -1,10 +1,10 @@
const assert = require('assert'); const assert = require('assert');
const frappe = require('frappe-core'); const frappe = require('frappe-core');
const helpers = require('./helpers');
describe('Controller', () => { describe('Controller', () => {
before(async function() { before(async function() {
await frappe.init(); await helpers.init_sqlite();
await frappe.db.migrate();
}); });
it('should call controller method', async () => { it('should call controller method', async () => {

View File

@ -1,10 +1,10 @@
const assert = require('assert'); const assert = require('assert');
const frappe = require('frappe-core'); const frappe = require('frappe-core');
const helpers = require('./helpers');
describe('Database', () => { describe('Database', () => {
before(async function() { before(async function() {
await frappe.init(); await helpers.init_sqlite();
await frappe.db.migrate();
}); });
it('should insert and get values', async () => { it('should insert and get values', async () => {

View File

@ -1,10 +1,10 @@
const assert = require('assert'); const assert = require('assert');
const frappe = require('frappe-core'); const frappe = require('frappe-core');
const helpers = require('./helpers');
describe('Document', () => { describe('Document', () => {
before(async function() { before(async function() {
await frappe.init(); await helpers.init_sqlite();
await frappe.db.migrate();
}); });
it('should insert a doc', async () => { it('should insert a doc', async () => {

View File

@ -1,10 +1,10 @@
const assert = require('assert'); const assert = require('assert');
const frappe = require('frappe-core'); const frappe = require('frappe-core');
const helpers = require('./helpers');
describe('Meta', () => { describe('Meta', () => {
before(async function() { before(async function() {
await frappe.init(); await helpers.init_sqlite();
await frappe.db.migrate();
}); });
it('should get init from json file', () => { it('should get init from json file', () => {

View File

@ -1,10 +1,10 @@
const assert = require('assert'); const assert = require('assert');
const frappe = require('frappe-core'); const frappe = require('frappe-core');
const helpers = require('./helpers');
describe('Models', () => { describe('Models', () => {
before(async function() { before(async function() {
await frappe.init(); await helpers.init_sqlite();
await frappe.db.migrate();
}); });
it('should get todo json', () => { it('should get todo json', () => {

View File

@ -1,22 +1,33 @@
const assert = require('assert'); const assert = require('assert');
const frappe = require('frappe-core'); const frappe = require('frappe-core');
const fetch = require('node-fetch'); const fetch = require('node-fetch');
const helpers = require('./helpers');
const { spawn } = require('child_process');
const process = require('process');
describe('Models', () => { // create a copy of frappe
var test_server;
describe('REST', () => {
before(async function() { before(async function() {
var app = require('express')(); await helpers.init_sqlite();
await frappe.init(); test_server = spawn('node', ['frappe/tests/test_server.js'], {
frappe.init_app(app); stdio: [0, 'pipe', 'pipe' ]
await frappe.start(); });
// wait for server to start
await frappe.sleep(1);
}); });
after(() => { after(() => {
frappe.close(); frappe.close();
test_server.kill();
}); });
it('should create a document', async () => { it('should create a document', async () => {
let res = await fetch('http://localhost:8000/api/resource/todo', { let res = await fetch('http://localhost:8000/api/resource/todo', {
method: 'post', method: 'POST',
headers: { headers: {
'Accept': 'application/json', 'Accept': 'application/json',
'Content-Type': 'application/json' 'Content-Type': 'application/json'
@ -29,9 +40,8 @@ describe('Models', () => {
}); });
// it('should create a document with rest backend', async () => { // it('should create a document with rest backend', async () => {
// frappe.set_backend('rest', {
// server: 'http://localhost:8000' // frappe.init_db('rest', { server: 'http://localhost:8000' });
// });
// let doc = await frappe.get_doc({doctype: 'ToDo', subject: 'test rest backend 1'}); // let doc = await frappe.get_doc({doctype: 'ToDo', subject: 'test rest backend 1'});
// await doc.insert(); // await doc.insert();

View File

@ -0,0 +1,14 @@
const app = require('express')();
const frappe = require('frappe-core');
async function start_server() {
console.log('Starting test server...');
await frappe.init();
await frappe.init_db('sqlite', {db_path: 'test.db'});
await frappe.init_app(app);
await frappe.start();
}
if (require.main === module) {
start_server();
}

View File

@ -19,5 +19,10 @@ module.exports = {
// number // number
return value + ''; return value + '';
} }
},
async sleep(seconds) {
return new Promise(resolve => {
setTimeout(resolve, seconds * 1000);
});
} }
} }

View File

@ -12,7 +12,6 @@
"express": "^4.16.2", "express": "^4.16.2",
"node-fetch": "^1.7.3", "node-fetch": "^1.7.3",
"nodemon": "^1.14.7", "nodemon": "^1.14.7",
"sql.js": "^0.4.0",
"sqlite3": "^3.1.13", "sqlite3": "^3.1.13",
"walk": "^2.3.9" "walk": "^2.3.9"
}, },