(greatest) Open Api Test library of all times!
The oat
package makes it very easy to test your API via an OpenAPI specification. It:
- 🤝 validates request and response parameter
- 🧬 generates multiple tests based on different security or parameter combinations
- 🧩 is compatible to all JavaScript testrunner
The following example shows a simple API test using Vitest:
import { describe, it } from 'vitest'
import { Testplan, URLParam, APIKeyAuth } from 'oat'
import type { OpenAPIV3 } from 'openapi-types'
import { specification } from './openapi-specification.json' assert { type: 'json' }
const urlParam = new URLParam({ id: '39f07889-1072-48df-8ca6-9d6726b5e525' })
const apiToken = new APIKeyAuth('Authorization', 'codeless-qa-b82b312d-4d44-40a3-bb5a-02529417e2d7', 'header')
describe('/api/specifications/{id}', () => {
const plan = new Testplan(specification as OpenAPIV3.Document)
plan.runTest('delete', '/api/specifications/{id}')
.withPayloads(urlParam)
.expect(401) // fails due to missing auth
plan.runTest('get', '/api/specifications/{id}')
.withSecuritySchemes([apiToken])
.withPayloads(urlParam)
.expect(200)
plan.runWith(it)
})
Install the package via:
npm i oat
The following primitives are available for composing your API tests.
A test plan composes one or multiple API tests based on provided security schemas and payload. To create an instance pass in an OpenAPI v3 specification as payload.
const plan = new Testplan(specification)
Creates a test penetrating a specific endpoint that can be contain different security schemas or payloads. The method returns an instance of a Test
.
plan.runTest('get', '/api/specifications/{id}')
Select a server from the specification to run the test agains, e.g. given the following server defintion:
{
"servers": [
{
"url": "https://staging.gigantic-server.com/v1",
"description": "Staging server"
},
{
"url": "https://{username}.gigantic-server.com:{port}/{basePath}",
"description": "The production API server",
"variables": {
"username": {
"default": "demo",
"description": "this value is assigned by the service provider, in this example `gigantic-server.com`"
},
"port": {
"enum": [
"8443",
"443"
],
"default": "8443"
},
"basePath": {
"default": "v2"
}
}
}
]
}
You can select a server either via the index or the URL, e.g.:
plan.usingServer(0) // selects Staging server
plan.usingServer('https://staging.gigantic-server.com/v1') // selects Staging server
plan.usingServer(1, { username: 'demo', port: '8443', basePath: 'v2' }) // selects custom server with parameter
Test function of the test framework of your choice, e.g. Vitest, Mocha etc. The provided test function should match the following interface:
type FrameworkFn = ((title: string, fn: (() => void)) => unknown)
type FrameworkAPI = FrameworkFn & {
only?: FrameworkFn
skip?: FrameworkFn
}
For above mentioned frameworks, it would be simply:
import { describe, it } from 'vitest'
plan.runWith(it)
A test represents one or multiple API request to a certain endpoint.
Allows to attach one or multiple security schemas to the test plan.
import { Testplan, APIKeyAuth } from 'oat'
const apiToken = new APIKeyAuth('Authorization', 'codeless-qa-b82b312d-4d44-40a3-bb5a-02529417e2d7', 'header')
const plan = new Testplan(specification)
plan.runTest('delete', '/api/specifications/{id}')
.withSecuritySchemes([apiToken])
Allows to attach one or multiple payload schemas to the test plan.
import { Testplan, URLParam, BodyPayload } from 'oat'
const urlParam = new URLParam({ id: '39f07889-1072-48df-8ca6-9d6726b5e525' })
const tokenPayload = new BodyPayload({ name: 'foobar', expires: null })
const plan = new Testplan(specification as OpenAPIV3.Document)
plan.runTest('delete', '/api/specifications/{id}')
.withPayloads([urlParam, tokenPayload])
Defines the expected status code and therefor response format.
import { Testplan } from 'oat'
const plan = new Testplan(specification)
plan.runTest('delete', '/api/specifications/{id}').expect(401)
A security object to be passed into a withSecuritySchemes
function. Oat will create individual test for every security object passed into withSecuritySchemes
.
Oat supports the following auth mechanism:
- Basic auth via
BasicAuth
class - Bearer tokens via
BearerAuth
class - Custom Headers via
APIKeyAuth
class
If called on the object, all test containing this security object will be skipped.
import { Testplan, APIKeyAuth } from 'oat'
const apiToken = new APIKeyAuth('Authorization', 'codeless-qa-b82b312d-4d44-40a3-bb5a-02529417e2d7', 'header')
apiToken.skip()
const plan = new Testplan(specification)
plan.runTest('delete', '/api/specifications/{id}')
.withSecuritySchemes([apiToken]) // test will be skipped
Extends from SecuritySchemeObject
.
A security object that represents a Basic Authentification header key.
import { BasicAuth } from 'oat'
const basicAuth = new BasicAuth('admin', 'password')
Extends from SecuritySchemeObject
.
A security object that represents a bearer token key.
import { BearerAuth } from 'oat'
const basicAuth = new BearerAuth('codeless-qa-b82b312d-4d44-40a3-bb5a-02529417e2d7')
Extends from SecuritySchemeObject
.
A security object that represents a key/value header pair.
import { APIKeyAuth } from 'oat'
const apiToken = new APIKeyAuth('Authorization', 'codeless-qa-b82b312d-4d44-40a3-bb5a-02529417e2d7')
Extends from SecuritySchemeObject
.
Allows to combine multiple security schemas for a single test, e.g. when an endpoint requires multiple auth mechanism at once.
import { CombinedSecuritySchemes, APIKeyAuth, BasicAuth } from 'oat'
const authMethodHeader = new APIKeyAuth('x-auth-method', 'basic-auth')
const basicAuth = new BasicAuth('admin', 'password')
const combinedSecScheme = new CombinedSecuritySchemes([ authMethodHeader, basicAuth ])
A payload object to be passed into a withPayloads
function. Oat will create individual test for every payload object passed into withPayloads
.
Oat supports the following payloads:
- URL query parameter via
QueryParam
class - URL path parameter via
URLParam
class - Body payload via
BodyPayload
class
If called on the object, all test containing this security object will be skipped.
import { Testplan, APIKeyAuth } from 'oat'
const urlParam = new URLParam({ id: '39f07889-1072-48df-8ca6-9d6726b5e525' })
urlParam.skip()
const plan = new Testplan(specification)
plan.runTest('delete', '/api/specifications/{id}')
.withPayloads([urlParam]) // test will be skipped
Extends from PayloadObject
.
A payload object to define query parameters.
import { Testplan, QueryParam } from 'oat'
const queryParam = new QueryParam({
name: 'foobar',
type: 'token'
})
const plan = new Testplan(specification)
plan.runTest('delete', '/api/specifications/{id}')
.withPayloads([queryParam]) // creates a request to "/api/specifications/{id}?name=foobar&type=token"
Extends from PayloadObject
.
A payload object to define parameters within the url.
import { Testplan, URLParam } from 'oat'
const urlParam = new URLParam({ id: '39f07889' })
const plan = new Testplan(specification)
plan.runTest('delete', '/api/specifications/{id}')
.withPayloads([urlParam]) // creates a request to "/api/specifications/39f07889"
Extends from PayloadObject
.
Sets a request body payload.
import { Testplan, BodyPayload } from 'oat'
const jsonBody = new BodyPayload({ some: 'payload' })
const streamBody = new BodyPayload(Buffer.from('...'))
const plan = new Testplan(specification)
plan.runTest('delete', '/api/specifications/{id}')
.withPayloads([jsonBody, streamBody])
Extends from PayloadObject
.
Allows to combine multiple payload objects for a single test, e.g. when an endpoint contains an url parameter and body payload.
import { CombinedPayload, URLParam, BodyPayload } from 'oat'
const jsonBody = new BodyPayload({ some: 'payload' })
const urlParam = new URLParam({ id: '39f07889' })
const combinedPayload = new CombinedPayload([ jsonBody, jsonBody ])
Apache 2 License © 2024-PRESENT CodelessQA