feat: yaml lang - parseRequest and stringifyRequest

This commit is contained in:
Anoop M D
2025-02-06 19:41:38 +05:30
parent 4598acd068
commit 0b19b26ce7
11 changed files with 1195 additions and 2 deletions

View File

@@ -0,0 +1,38 @@
{
"name": "Get User GraphQL",
"seq": 1,
"request": {
"method": "POST",
"url": "https://api.example.com/graphql",
"headers": [
{
"name": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "graphql",
"graphql": {
"query": "query GetUser($id: ID!) {\n user(id: $id) {\n id\n name\n email\n }\n}",
"variables": "{\n \"id\": \"123\"\n}"
}
},
"auth": {
"mode": "bearer",
"bearer": {
"token": "jwt-token"
}
},
"vars": {
"req": [
{
"name": "userId",
"value": "123"
}
]
},
"script": {
"req": "// Pre-request script for GraphQL"
}
}
}

View File

@@ -0,0 +1,36 @@
meta:
name: Get User GraphQL
seq: 1
graphql:
method: post
url: https://api.example.com/graphql
params:
query: []
path: []
headers:
- name: Content-Type
value: application/json
body:
type: graphql
query: |-
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
variables: |-
{
"id": "123"
}
auth:
type: bearer
bearer:
token: jwt-token
vars:
pre-request:
- name: userId
value: '123'
scripts:
pre-request: // Pre-request script for GraphQL

View File

@@ -0,0 +1,70 @@
{
"name": "HTTP Methods",
"seq": 1,
"request": {
"method": "POST",
"url": "https://api.example.com/users",
"headers": [
{
"name": "Content-Type",
"value": "application/json",
"description": "Content type header",
"enabled": true
},
{
"name": "Accept",
"value": "application/json",
"enabled": false
}
],
"params": [
{
"name": "userId",
"value": "123",
"type": "path",
"description": "User ID parameter",
"enabled": true
},
{
"name": "filter",
"value": "active",
"type": "query",
"enabled": false
}
],
"body": {
"mode": "json",
"json": "{\n \"name\": \"John Doe\",\n \"email\": \"john@example.com\"\n}"
},
"auth": {
"mode": "basic",
"basic": {
"username": "admin",
"password": "secret"
}
},
"vars": {
"req": [
{
"name": "userId",
"value": "123",
"description": "User ID variable",
"enabled": true
}
],
"res": [
{
"name": "token",
"value": "response.token",
"enabled": false
}
]
},
"script": {
"req": "// Pre-request script\nconsole.log('pre-request');",
"res": "// Post-response script\nconsole.log('post-response');"
},
"tests": "// Test script\nassert.response.status === 200;",
"docs": "# User Creation API\nThis endpoint creates a new user."
}
}

View File

@@ -0,0 +1,58 @@
meta:
name: HTTP Methods
seq: 1
http:
method: post
url: https://api.example.com/users
params:
query:
- name: filter
value: active
type: query
disabled: true
path:
- name: userId
value: '123'
type: path
description: User ID parameter
headers:
- name: Content-Type
value: application/json
description: Content type header
- name: Accept
value: application/json
disabled: true
body:
type: json
data: |-
{
"name": "John Doe",
"email": "john@example.com"
}
auth:
type: basic
basic:
username: admin
password: secret
vars:
pre-request:
- name: userId
value: '123'
description: User ID variable
post-response:
- name: token
value: response.token
disabled: true
scripts:
pre-request: |-
// Pre-request script
console.log('pre-request');
post-response: |-
// Post-response script
console.log('post-response');
tests: |-
// Test script
assert.response.status === 200;
docs: |-
# User Creation API
This endpoint creates a new user.

View File

@@ -0,0 +1,103 @@
const { stringifyRequest } = require('../../src');
const yaml = require('js-yaml');
const path = require('path');
const fs = require('fs');
describe('GraphQL Request Handling', () => {
const loadFixture = (filename) => {
const filePath = path.join(__dirname, '__fixtures__', filename);
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
};
it('should generate exact YAML matching the fixture', () => {
const json = loadFixture('graphql-request.json');
const expectedYaml = fs.readFileSync(
path.join(__dirname, '__fixtures__', 'graphql-request.yml'),
'utf8'
);
const generatedYaml = stringifyRequest(json);
// Normalize line endings and whitespace for comparison
const normalizeString = (str) => str.replace(/\r\n/g, '\n').trim();
expect(normalizeString(generatedYaml)).toBe(normalizeString(expectedYaml));
});
it('should correctly format GraphQL request', () => {
const json = loadFixture('graphql-request.json');
const result = yaml.load(stringifyRequest(json));
// Verify GraphQL section exists instead of HTTP
expect(result.graphql).toBeDefined();
expect(result.http).toBeUndefined();
// Verify basic properties
expect(result.graphql.method).toBe('post');
expect(result.graphql.url).toBe('https://api.example.com/graphql');
// Verify headers
expect(result.graphql.headers).toHaveLength(1);
expect(result.graphql.headers[0]).toEqual({
name: 'Content-Type',
value: 'application/json'
});
// Verify body
expect(result.graphql.body).toEqual({
type: 'graphql',
query: 'query GetUser($id: ID!) {\n user(id: $id) {\n id\n name\n email\n }\n}',
variables: '{\n \"id\": \"123\"\n}'
});
// Verify auth
expect(result.graphql.auth).toEqual({
type: 'bearer',
bearer: {
token: 'jwt-token'
}
});
// Verify vars
expect(result.vars['pre-request']).toHaveLength(1);
expect(result.vars['pre-request'][0]).toEqual({
name: 'userId',
value: '123'
});
// Verify scripts
expect(result.scripts['pre-request']).toBe('// Pre-request script for GraphQL');
});
it('should handle GraphQL request without variables', () => {
const json = loadFixture('graphql-request.json');
json.request.body.graphql.variables = '';
const result = yaml.load(stringifyRequest(json));
expect(result.graphql.body.variables).toBe('');
});
it('should handle GraphQL request without optional components', () => {
const json = loadFixture('graphql-request.json');
// Remove optional components
delete json.request.auth;
delete json.request.vars;
delete json.request.script;
const result = yaml.load(stringifyRequest(json));
expect(result.graphql.auth).toEqual({ type: 'none' });
expect(result.vars).toBeUndefined();
expect(result.scripts).toBeUndefined();
});
it('should detect GraphQL request based on body mode', () => {
const json = loadFixture('graphql-request.json');
// Change URL but keep GraphQL body
json.request.url = 'https://api.example.com/not-graphql';
const result = yaml.load(stringifyRequest(json));
expect(result.graphql).toBeDefined();
expect(result.http).toBeUndefined();
});
});

View File

@@ -0,0 +1,244 @@
const { stringifyRequest } = require('../../src');
const yaml = require('js-yaml');
const path = require('path');
const fs = require('fs');
describe('HTTP Request Handling', () => {
const loadFixture = (filename) => {
const filePath = path.join(__dirname, '__fixtures__', filename);
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
};
it('should generate exact YAML matching the fixture', () => {
const json = loadFixture('http-request.json');
const expectedYaml = fs.readFileSync(
path.join(__dirname, '__fixtures__', 'http-request.yml'),
'utf8'
);
const generatedYaml = stringifyRequest(json);
// Normalize line endings and whitespace for comparison
const normalizeString = (str) => str.replace(/\r\n/g, '\n').trim();
expect(normalizeString(generatedYaml)).toBe(normalizeString(expectedYaml));
});
it('should correctly format basic HTTP request', () => {
const json = loadFixture('http-request.json');
const result = yaml.load(stringifyRequest(json));
// Verify HTTP section exists instead of GraphQL
expect(result.http).toBeDefined();
expect(result.graphql).toBeUndefined();
// Verify basic properties
expect(result.meta.name).toBe('HTTP Methods');
expect(result.meta.seq).toBe(1);
expect(result.http.method).toBe('post');
expect(result.http.url).toBe('https://api.example.com/users');
});
it('should handle request with query parameters', () => {
const json = loadFixture('http-request.json');
const result = yaml.load(stringifyRequest(json));
expect(result.http.params.query).toEqual([
{
name: 'filter',
value: 'active',
type: 'query',
disabled: true
}
]);
});
it('should handle request with path parameters', () => {
const json = loadFixture('http-request.json');
const result = yaml.load(stringifyRequest(json));
expect(result.http.params.path).toEqual([
{
name: 'userId',
value: '123',
type: 'path',
description: 'User ID parameter'
}
]);
});
it('should handle request with headers', () => {
const json = loadFixture('http-request.json');
const result = yaml.load(stringifyRequest(json));
expect(result.http.headers).toEqual([
{
name: 'Content-Type',
value: 'application/json',
description: 'Content type header'
},
{
name: 'Accept',
value: 'application/json',
disabled: true
}
]);
});
describe('Body Handling', () => {
it('should handle JSON body', () => {
const json = loadFixture('http-request.json');
const result = yaml.load(stringifyRequest(json));
expect(result.http.body).toEqual({
type: 'json',
data: '{\n "name": "John Doe",\n "email": "john@example.com"\n}'
});
});
it('should handle form-urlencoded body', () => {
const json = loadFixture('http-request.json');
json.request.body = {
mode: 'formUrlEncoded',
formUrlEncoded: [
{ name: 'username', value: 'johndoe', description: 'Username field', enabled: true },
{ name: 'password', value: 'secret', enabled: false }
]
};
const result = yaml.load(stringifyRequest(json));
expect(result.http.body).toEqual({
type: 'form-urlencoded',
data: [
{ name: 'username', value: 'johndoe', description: 'Username field' },
{ name: 'password', value: 'secret', disabled: true }
]
});
});
it('should handle multipart-form body', () => {
const json = loadFixture('http-request.json');
json.request.body = {
mode: 'multipartForm',
multipartForm: [
{ name: 'file', value: ['path/to/file'], type: 'file', enabled: true },
{ name: 'description', value: 'profile photo', type: 'text', enabled: true }
]
};
const result = yaml.load(stringifyRequest(json));
expect(result.http.body).toEqual({
type: 'multipart-form',
data: [
{ name: 'file', value: ['path/to/file'], type: 'file' },
{ name: 'description', value: 'profile photo', type: 'text' }
]
});
});
});
describe('Auth Handling', () => {
it('should handle basic auth', () => {
const json = loadFixture('http-request.json');
const result = yaml.load(stringifyRequest(json));
expect(result.http.auth).toEqual({
type: 'basic',
basic: {
username: 'admin',
password: 'secret'
}
});
});
it('should handle bearer auth', () => {
const json = loadFixture('http-request.json');
json.request.auth = {
mode: 'bearer',
bearer: { token: 'xyz123' }
};
const result = yaml.load(stringifyRequest(json));
expect(result.http.auth).toEqual({
type: 'bearer',
bearer: {
token: 'xyz123'
}
});
});
it('should handle oauth2 password grant', () => {
const json = loadFixture('http-request.json');
json.request.auth = {
mode: 'oauth2',
oauth2: {
grantType: 'password',
accessTokenUrl: 'https://api.example.com/oauth/token',
username: 'user',
password: 'pass',
clientId: 'client123',
clientSecret: 'secret123',
scope: 'read write'
}
};
const result = yaml.load(stringifyRequest(json));
expect(result.http.auth).toEqual({
type: 'oauth2',
oauth2: {
grant_type: 'password',
access_token_url: 'https://api.example.com/oauth/token',
username: 'user',
password: 'pass',
client_id: 'client123',
client_secret: 'secret123',
scope: 'read write'
}
});
});
});
describe('Variables and Scripts', () => {
it('should handle pre-request variables', () => {
const json = loadFixture('http-request.json');
const result = yaml.load(stringifyRequest(json));
expect(result.vars['pre-request']).toEqual([
{ name: 'userId', value: '123', description: 'User ID variable' }
]);
});
it('should handle post-response variables', () => {
const json = loadFixture('http-request.json');
const result = yaml.load(stringifyRequest(json));
expect(result.vars['post-response']).toEqual([
{ name: 'token', value: 'response.token', disabled: true }
]);
});
it('should handle scripts', () => {
const json = loadFixture('http-request.json');
const result = yaml.load(stringifyRequest(json));
expect(result.scripts['pre-request']).toBe('// Pre-request script\nconsole.log(\'pre-request\');');
expect(result.scripts['post-response']).toBe('// Post-response script\nconsole.log(\'post-response\');');
});
});
it('should handle tests and docs', () => {
const json = loadFixture('http-request.json');
const result = yaml.load(stringifyRequest(json));
expect(result.tests).toBe('// Test script\nassert.response.status === 200;');
expect(result.docs).toBe('# User Creation API\nThis endpoint creates a new user.');
});
it('should handle disabled components', () => {
const json = loadFixture('http-request.json');
json.request.headers[0].enabled = false;
json.request.params[0].enabled = false;
const result = yaml.load(stringifyRequest(json));
expect(result.http.headers[0].disabled).toBe(true);
expect(result.http.params.query[0].disabled).toBe(true);
});
});