Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Run NodeJS and Browser Tests with Odoo

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest

services:
db:
image: postgres:16
env:
POSTGRES_USER: odoo
POSTGRES_PASSWORD: odoo
POSTGRES_DB: test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install dependencies
run: npm install

- name: Init Odoo and crate database
run: |
docker run -d --network host \
-e HOST=localhost \
-e USER=odoo \
-e PASSWORD=odoo \
-e DATABASE=odoo \
odoo:16 \
odoo --db_host=localhost --db_user=odoo --db_password=odoo --init=base --database=odoo

- name: Wait for Odoo to be ready
run: |
echo "Waiting for Odoo..."
for i in {1..30}; do
if curl -s http://localhost:8069 | grep -q "Odoo"; then
echo "Odoo is ready!"
break
fi
sleep 2
done

- name: Run Node.js unit tests
run: npm run test

- name: Run Browser tests
run: npm run test-browser
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ Thumbs.db
.vscode/
.idea/

# Test result of playwright
test-results/

# Test coverage
coverage/

Expand Down
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

112 changes: 97 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,66 @@
# js-odoo-rpc

[![Tests](https://github.com/rlizana/js-odoo-rpc/actions/workflows/test.yml/badge.svg)](https://github.com/rlizana/js-odoo-rpc/actions)
[![npm](https://img.shields.io/npm/v/js-odoo-rpc)](https://www.npmjs.com/package/js-odoo-rpc)
[![npm](https://img.shields.io/npm/dt/js-odoo-rpc)](https://www.npmjs.com/package/js-odoo-rpc)
[![GitHub](https://img.shields.io/github/license/rlizana/js-odoo-rpc?label=license)](https://github.com/rlizana/js-odoo-rpc/blob/main/LICENSE)


**js-odoo-rpc** is a lightweight JavaScript/TypeScript library to interact with Odoo (tested on Odoo 16, 17, 18) via JSON-RPC and session-based authentication.

It works in both **Node.js** and **browser environments**, making it suitable for frontend frameworks (Svelte, Vue, React) and backend scripts.

---

## Features
## Features

- Session-based login (`/web/session/authenticate`)
- Works with both Node.js and browser fetch
- Automatic cookie handling (with `fetch-cookie` in Node)
- Session-based login (`/web/session/authenticate`)
- JSON-RPC calls to any Odoo model/method
- Simplified API with `env('model')`
- Report printing via `/report/pdf/...` (PDF download)
- Built-in context and CSRF token support
- Works with both Node.js and browser fetch

# How it works

Same code for Node.js and browser. The library uses `fetch` for HTTP requests, and in Node.js, it uses `fetch-cookie` to handle cookies automatically.

```js
import { Odoo } from 'js-odoo-rpc'

const odoo = new Odoo('http://localhost:8069', 'test')
await odoo.login('admin', 'admin')

// Search and partners and read their names
let partners = await odoo
.env('res.partner')
.search([['name', 'ilike', 'Azure%']])
.read(['name'])

// Modify a partner
let result = await odoo
.env('res.partner')
.write([partners[0].id], { name: 'New name' })

// Create a partner
let partner_id = await odoo
.env('res.partner')
.create({ name: 'New name' })

// Remove a partner
let result = await odoo
.env('res.partner')
.unlink([partner_id])

// Call any method
let names = await odoo
.env('res.partner')
.call('name_search', ['Azure%'], 0, 10)



```

---

Expand All @@ -23,15 +69,19 @@ It works in both **Node.js** and **browser environments**, making it suitable fo
### Node.js

```bash
npm install js-odoo-rpc cross-fetch fetch-cookie
npm install js-odoo-rpc
```

### Browser (ESM)

Use a bundler like Vite, Webpack or Rollup and import the browser version:

```js
import { connect, env } from './dist/js-odoo-rpc.browser.js'
import { Odoo } from 'js-odoo-rpc'

const odoo = new Odoo('http://localhost:8069', 'test')
await odoo.login('admin', 'admin')

```

---
Expand All @@ -41,15 +91,10 @@ import { connect, env } from './dist/js-odoo-rpc.browser.js'
### 1. Connect to Odoo

```ts
import { connect, is_loged } from 'js-odoo-rpc'

await connect({
url: 'http://localhost:8069',
dbname: 'test',
username: 'admin',
password: 'admin',
verbose: true
})
import { Odoo } from 'js-odoo-rpc'

const odoo = new Odoo('http://localhost:8069', 'test')
await odoo.login('admin', 'admin')

console.log(is_loged()) // true if login was successful
```
Expand Down Expand Up @@ -92,7 +137,6 @@ await env('res.partner').call('default_get', [['name', 'email']])

```ts
const buffer = await env('sale.order').print('sale.report_saleorder', [7])

const blob = new Blob([buffer], { type: 'application/pdf' })
const url = URL.createObjectURL(blob)
window.open(url)
Expand All @@ -116,3 +160,41 @@ npm run shell

This will start a REPL session where you can type in your Odoo commands and see the results in real-time. It's a great way to test out different methods and see how they work without needing to write a full script.
You can also use the REPL to test out different models and methods, making it a powerful tool for exploring the Odoo API.

---

## Tests

To run unit and browser tests, you need an Odoo environment accessible at `localhost:8069` with a database named `odoo`. You can easily set this up using Docker Compose:

```bash
cd tests/docker
docker compose up
```

This will start an Odoo container and a PostgreSQL container, exposing Odoo on port 8069 of your local machine and automatically creating the `odoo` database with user and password `odoo`.

> **Warning:** Do not use a production database for testing. These tests may create, modify, and delete data. Always use a test database.

Once the environment is up, you can run the tests as many times as you want on the same database.

### Unit tests (Node.js)

From the project root, run:

```bash
npm run test
```

This will run the unit tests using Vitest, connecting to the Docker Odoo.

### Browser tests (Playwright)

To run end-to-end browser tests:

```bash
npm run test-browser
```

This will run the Playwright tests, also against the Odoo instance exposed at `localhost:8069`.

17 changes: 14 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
{
"type": "module",
"name": "js-odoo-rpc",
"version": "1.0.0",
"version": "1.0.2",
"description": "A lightweight JS/TS library to interact with Odoo via JSON-RPC and session",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
},
"files": [
"dist"
],
"scripts": {
"dev": "vitest watch",
"test": "vitest run",
"test-browser": "playwright test",
"lint": "eslint . --ext .ts",
"format": "prettier --write .",
"shell": "tsx scripts/repl.ts",
"build": "node build.mjs"
"build": "tsup"
},
"repository": {
"type": "git",
Expand All @@ -28,6 +37,7 @@
"api"
],
"devDependencies": {
"@playwright/test": "^1.52.0",
"@types/node": "^22.14.1",
"@typescript-eslint/eslint-plugin": "^7.5.0",
"@typescript-eslint/parser": "^7.5.0",
Expand All @@ -37,6 +47,7 @@
"eslint-plugin-svelte": "^2.35.1",
"jsdom": "^26.0.0",
"prettier": "^3.2.5",
"tsup": "^8.4.0",
"tsx": "^4.19.3",
"typescript": "^5.4.5",
"vitest": "^1.4.0"
Expand Down
11 changes: 11 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { defineConfig } from '@playwright/test'

export default defineConfig({
testDir: './tests/browser',
use: {
baseURL: 'http://localhost:8080',
headless: true,
screenshot: 'only-on-failure',
video: 'retain-on-failure'
}
})
Loading