initial commit
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules/
|
||||
.env
|
||||
*.log
|
||||
|
||||
29
Adressen.gql
Normal file
29
Adressen.gql
Normal file
@@ -0,0 +1,29 @@
|
||||
query {
|
||||
getAddresses(input: {
|
||||
take: 10
|
||||
}) {
|
||||
items {
|
||||
id: id
|
||||
name: name
|
||||
first_name: firstName
|
||||
last_name: lastName
|
||||
extra: addition
|
||||
street: primaryPostalAddress { street }
|
||||
zip_code: primaryPostalAddress { postalCode }
|
||||
city: primaryPostalAddress { city }
|
||||
homepage: homepage
|
||||
phone_number_1: mainPhone
|
||||
phone_number_2: phone2
|
||||
phone_number_3: mobilePhone
|
||||
phone_number_4: fax
|
||||
email: defaultEmail
|
||||
alternative_email: email2
|
||||
customer_reference: debitor { identifier }
|
||||
supplier_reference: creditor { identifier }
|
||||
sales_lead_reference: referenceId
|
||||
reference: referenceId
|
||||
receipt_block: documentBlockOut
|
||||
inactive: inactive
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Artikel.gql
Normal file
15
Artikel.gql
Normal file
@@ -0,0 +1,15 @@
|
||||
query {
|
||||
getProducts(input: { take: 10 }) {
|
||||
items {
|
||||
phxId: id
|
||||
id: identifier
|
||||
name: description
|
||||
manufacturer_number: mpn
|
||||
ean: gtin,
|
||||
extra: addition,
|
||||
quantity_unit: unit { identifier }
|
||||
productType
|
||||
inactive: inactive
|
||||
}
|
||||
}
|
||||
}
|
||||
10
Artikelgruppen.gql
Normal file
10
Artikelgruppen.gql
Normal file
@@ -0,0 +1,10 @@
|
||||
query {
|
||||
getProductGroups(input: { take: 10 }) {
|
||||
items {
|
||||
phxId: id
|
||||
id: identifier
|
||||
name: description
|
||||
parent_id: parentId #not the identifier id
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Aufträge.gql
Normal file
15
Aufträge.gql
Normal file
@@ -0,0 +1,15 @@
|
||||
query {
|
||||
getDocuments(input: {
|
||||
take: 10,
|
||||
documentDefinitionIdentifier: ["SO"]
|
||||
}) {
|
||||
items {
|
||||
id: identifier
|
||||
documentPostalAddress {
|
||||
name: recipient
|
||||
description: addition
|
||||
}
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
49
Belege.gql
Normal file
49
Belege.gql
Normal file
@@ -0,0 +1,49 @@
|
||||
query {
|
||||
getDocuments(input: {
|
||||
take: 10,
|
||||
documentDefinitionIdentifier: ["OF", "SO", "DL", "INV"]
|
||||
}) {
|
||||
items {
|
||||
id: id
|
||||
number: identifier
|
||||
address_reference: debitorCreditorIdentifier
|
||||
documentPostalAddress {
|
||||
name: recipient
|
||||
description: addition
|
||||
city: city
|
||||
country: countryIso
|
||||
street: street
|
||||
zip: postalCode
|
||||
},
|
||||
external_order: theirReference
|
||||
contact_person: theirSignature
|
||||
own_reference: ourSignature
|
||||
address_id: addressId
|
||||
status
|
||||
creatorEmployee {
|
||||
created_by_name: lastName
|
||||
}
|
||||
currency: currency
|
||||
customFields {
|
||||
custom_field_1: text1
|
||||
custom_field_2: text2
|
||||
}
|
||||
date: date,
|
||||
deliveryPostalAddress {
|
||||
delivery_city: city
|
||||
delivery_name: recipient
|
||||
}
|
||||
discount: discountPercentage
|
||||
extra_text: notes
|
||||
payment_condition: paymentReference
|
||||
payment_target: paymentTargetDays
|
||||
price: total
|
||||
total_price: totalWithTax
|
||||
profit: revenue
|
||||
tax: totalTax
|
||||
created_at: createdAt
|
||||
receipt_type_id: documentDefinitionIdentifier
|
||||
weight: grossWeight
|
||||
}
|
||||
}
|
||||
}
|
||||
4
gql todos/Aritkelpreise.gql
Normal file
4
gql todos/Aritkelpreise.gql
Normal file
@@ -0,0 +1,4 @@
|
||||
#TBD
|
||||
#SELECT *
|
||||
#FROM AP_ARTICLE_PRICE_CUSTOMER_MATRIX(:date, :articleIds, 'EUR')
|
||||
#ORDER BY [priority]
|
||||
0
gql todos/Ausgelieferte Artikel.gql
Normal file
0
gql todos/Ausgelieferte Artikel.gql
Normal file
23
package.json
Normal file
23
package.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "venabo-gql-templates",
|
||||
"version": "1.0.0",
|
||||
"description": "GraphQL test runner for Venabo API",
|
||||
"main": "run-tests.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"test": "node run-tests.js",
|
||||
"test:verbose": "node run-tests.js --verbose"
|
||||
},
|
||||
"keywords": [
|
||||
"graphql",
|
||||
"testing",
|
||||
"venabo"
|
||||
],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"chalk": "^5.6.2",
|
||||
"dotenv": "^16.4.5",
|
||||
"node-fetch": "^3.3.2"
|
||||
}
|
||||
}
|
||||
120
readme.md
Normal file
120
readme.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# Venabo GraphQL Templates
|
||||
|
||||
A simple JavaScript tool to run and test GraphQL queries against the Venabo API.
|
||||
|
||||
## Features
|
||||
|
||||
- 🚀 Automatically discovers and runs all `.gql` files in the directory
|
||||
- ✅ Validates GraphQL queries and mutations
|
||||
- 📊 Provides test results summary
|
||||
- 🔍 Verbose mode for detailed output
|
||||
- 🎨 Colorized terminal output
|
||||
|
||||
## Setup
|
||||
|
||||
1. Install dependencies:
|
||||
```bash
|
||||
yarn install
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Run all tests
|
||||
```bash
|
||||
yarn test
|
||||
```
|
||||
|
||||
Or directly:
|
||||
```bash
|
||||
node run-tests.js
|
||||
```
|
||||
|
||||
### Run with verbose output
|
||||
```bash
|
||||
yarn test:verbose
|
||||
```
|
||||
|
||||
Or:
|
||||
```bash
|
||||
node run-tests.js --verbose
|
||||
```
|
||||
|
||||
### Custom GraphQL Endpoint
|
||||
|
||||
Set the `GRAPHQL_ENDPOINT` environment variable to use a different endpoint:
|
||||
|
||||
```bash
|
||||
# Windows PowerShell
|
||||
$env:GRAPHQL_ENDPOINT="https://your-endpoint.com/graphql"; node run-tests.js
|
||||
|
||||
# Windows CMD
|
||||
set GRAPHQL_ENDPOINT=https://your-endpoint.com/graphql && node run-tests.js
|
||||
|
||||
# Linux/Mac
|
||||
GRAPHQL_ENDPOINT=https://your-endpoint.com/graphql node run-tests.js
|
||||
```
|
||||
|
||||
Default endpoint: `https://venabo.phx-erp.cloud/backend-api/admin-api`
|
||||
|
||||
### Custom Authorization Token
|
||||
|
||||
Set the `AUTH_TOKEN` environment variable to use a different Bearer token:
|
||||
|
||||
```bash
|
||||
# Windows PowerShell
|
||||
$env:AUTH_TOKEN="your-token-here"; node run-tests.js
|
||||
|
||||
# Windows CMD
|
||||
set AUTH_TOKEN=your-token-here && node run-tests.js
|
||||
|
||||
# Linux/Mac
|
||||
AUTH_TOKEN=your-token-here node run-tests.js
|
||||
```
|
||||
|
||||
**Note:** All requests include an `Authorization: Bearer <token>` header.
|
||||
|
||||
### Using .env File
|
||||
|
||||
You can create a `.env` file in the project root to store your configuration:
|
||||
|
||||
```env
|
||||
GRAPHQL_ENDPOINT=https://venabo.phx-erp.cloud/backend-api/admin-api
|
||||
AUTH_TOKEN=your-token-here
|
||||
```
|
||||
|
||||
The `.env` file is automatically loaded when you run the tests. Environment variables set in your shell will override values in the `.env` file.
|
||||
|
||||
## Test Files
|
||||
|
||||
Create `.gql` files in the project directory. Each file should contain a valid GraphQL query, mutation, or subscription:
|
||||
|
||||
**Example: `Artikel.gql`**
|
||||
```graphql
|
||||
query {
|
||||
getProducts(input: { take: 10 }) {
|
||||
items {
|
||||
id
|
||||
identifierAlias: identifier
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The tool will automatically:
|
||||
- Discover all `.gql` files
|
||||
- Extract the query/mutation/subscription
|
||||
- Send it to the GraphQL endpoint
|
||||
- Report success or failure
|
||||
|
||||
## Output
|
||||
|
||||
The tool provides:
|
||||
- ✅ Success indicators for passing tests
|
||||
- ❌ Error messages for failing tests
|
||||
- 📊 Summary statistics at the end
|
||||
- 🔍 Detailed output in verbose mode (including query content and response data)
|
||||
|
||||
## Exit Codes
|
||||
|
||||
- `0` - All tests passed
|
||||
- `1` - One or more tests failed
|
||||
145
run-tests.js
Normal file
145
run-tests.js
Normal file
@@ -0,0 +1,145 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import fetch from 'node-fetch';
|
||||
import dotenv from 'dotenv';
|
||||
import chalk from 'chalk';
|
||||
|
||||
// Load .env file
|
||||
dotenv.config();
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
// Configuration
|
||||
const GRAPHQL_ENDPOINT = process.env.GRAPHQL_ENDPOINT || 'https://venabo.phx-erp.cloud/backend-api/admin-api';
|
||||
const AUTH_TOKEN = process.env.AUTH_TOKEN;
|
||||
const VERBOSE = process.argv.includes('--verbose');
|
||||
|
||||
function log(message) {
|
||||
console.log(message);
|
||||
}
|
||||
|
||||
function parseGraphQLFile(filePath) {
|
||||
try {
|
||||
const content = fs.readFileSync(filePath, 'utf-8');
|
||||
const lines = content.split('\n');
|
||||
|
||||
// Extract query name and type
|
||||
const firstLine = lines[0].trim();
|
||||
const queryType = firstLine.startsWith('query') ? 'query' :
|
||||
firstLine.startsWith('mutation') ? 'mutation' :
|
||||
firstLine.startsWith('subscription') ? 'subscription' : 'query';
|
||||
|
||||
return {
|
||||
name: path.basename(filePath, '.gql'),
|
||||
type: queryType,
|
||||
query: content.trim(),
|
||||
};
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to parse ${filePath}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function runGraphQLTest(test) {
|
||||
try {
|
||||
log(`\n${chalk.cyan.bold('Testing:')} ${chalk.cyan(test.name)}`);
|
||||
|
||||
if (VERBOSE) {
|
||||
log(` ${chalk.gray('Type:')} ${chalk.yellow(test.type)}`);
|
||||
log(` ${chalk.gray('Query:')}`);
|
||||
console.log(test.query.split('\n').map(line => ` ${chalk.gray(line)}`).join('\n'));
|
||||
}
|
||||
|
||||
const response = await fetch(GRAPHQL_ENDPOINT, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${AUTH_TOKEN}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query: test.query,
|
||||
}),
|
||||
});
|
||||
|
||||
const text = await response.text();
|
||||
let result;
|
||||
try {
|
||||
result = JSON.parse(text);
|
||||
} catch (e) {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}. Response: ${text.substring(0, 200)}`);
|
||||
}
|
||||
|
||||
if (result.errors) {
|
||||
log(` ${chalk.red.bold('Errors found:')}`);
|
||||
result.errors.forEach(error => {
|
||||
log(` ${chalk.red('✗')} ${chalk.red(error.message)}`);
|
||||
if (VERBOSE && error.locations) {
|
||||
error.locations.forEach(loc => {
|
||||
log(` ${chalk.gray(`Line ${loc.line}, Column ${loc.column}`)}`);
|
||||
});
|
||||
}
|
||||
if (VERBOSE && error.path) {
|
||||
log(` ${chalk.gray(`Path: ${error.path.join('.')}`)}`);
|
||||
}
|
||||
});
|
||||
return { success: false, test, result };
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
log(` ${chalk.green.bold('✓ Success')}`);
|
||||
if (VERBOSE && result.data) {
|
||||
log(` ${chalk.gray('Response:')}`);
|
||||
console.log(JSON.stringify(result.data, null, 2));
|
||||
}
|
||||
|
||||
return { success: true, test, result };
|
||||
} catch (error) {
|
||||
log(` ${chalk.red.bold('✗ Failed:')} ${chalk.red(error.message)}`);
|
||||
return { success: false, test, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
log(chalk.bold.blue('Venabo GraphQL Test Runner\n'));
|
||||
log(`${chalk.gray('Endpoint:')} ${chalk.cyan(GRAPHQL_ENDPOINT)}`);
|
||||
|
||||
// Find all .gql files
|
||||
const files = fs.readdirSync(__dirname)
|
||||
.filter(file => file.endsWith('.gql'))
|
||||
.map(file => path.join(__dirname, file));
|
||||
|
||||
if (files.length === 0) {
|
||||
log(chalk.yellow('No .gql files found in the current directory'));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
log(`${chalk.gray('Found')} ${chalk.cyan(files.length)} ${chalk.gray('test file(s)\n')}`);
|
||||
|
||||
// Parse all test files
|
||||
const tests = files.map(parseGraphQLFile);
|
||||
|
||||
// Run all tests
|
||||
const results = await Promise.all(tests.map(runGraphQLTest));
|
||||
|
||||
// Summary
|
||||
const passed = results.filter(r => r.success).length;
|
||||
const failed = results.filter(r => !r.success).length;
|
||||
|
||||
log('\n' + chalk.gray('='.repeat(50)));
|
||||
log(chalk.bold('Summary:'));
|
||||
log(` ${chalk.green.bold('Passed:')} ${chalk.green(passed)}`);
|
||||
log(` ${chalk.red.bold('Failed:')} ${chalk.red(failed)}`);
|
||||
log(chalk.gray('='.repeat(50)) + '\n');
|
||||
|
||||
process.exit(failed > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
main().catch(error => {
|
||||
log(`\n${chalk.red.bold('Fatal error:')} ${chalk.red(error.message)}`);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
52
yarn.lock
Normal file
52
yarn.lock
Normal file
@@ -0,0 +1,52 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
chalk@^5.6.2:
|
||||
version "5.6.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.6.2.tgz#b1238b6e23ea337af71c7f8a295db5af0c158aea"
|
||||
integrity sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==
|
||||
|
||||
data-uri-to-buffer@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e"
|
||||
integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==
|
||||
|
||||
dotenv@^16.4.5:
|
||||
version "16.6.1"
|
||||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020"
|
||||
integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==
|
||||
|
||||
fetch-blob@^3.1.2, fetch-blob@^3.1.4:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9"
|
||||
integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==
|
||||
dependencies:
|
||||
node-domexception "^1.0.0"
|
||||
web-streams-polyfill "^3.0.3"
|
||||
|
||||
formdata-polyfill@^4.0.10:
|
||||
version "4.0.10"
|
||||
resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423"
|
||||
integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==
|
||||
dependencies:
|
||||
fetch-blob "^3.1.2"
|
||||
|
||||
node-domexception@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
|
||||
integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
|
||||
|
||||
node-fetch@^3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.2.tgz#d1e889bacdf733b4ff3b2b243eb7a12866a0b78b"
|
||||
integrity sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==
|
||||
dependencies:
|
||||
data-uri-to-buffer "^4.0.0"
|
||||
fetch-blob "^3.1.4"
|
||||
formdata-polyfill "^4.0.10"
|
||||
|
||||
web-streams-polyfill@^3.0.3:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b"
|
||||
integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==
|
||||
Reference in New Issue
Block a user