Skip to content

Commit

Permalink
Merge pull request #26 from BouyguesTelecom/feat/mesh-unit-tests
Browse files Browse the repository at this point in the history
✨ Unit tests for Mesh package
  • Loading branch information
arnaud authored Jul 22, 2024
2 parents b2da181 + b0de2fb commit b7d8842
Show file tree
Hide file tree
Showing 9 changed files with 743 additions and 5 deletions.
28 changes: 28 additions & 0 deletions .github/workflows/unit-tests-mesh.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Run Unit Tests for the graphql-mesh library

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

jobs:
unit-tests:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}

- name: Install dependencies
run: npm install

- name: Run tests
run: npm test -w graphql-mesh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Run Unit Tests for directive-spl library
name: Run Unit Tests for the directive-spl library

on:
push:
Expand Down
2 changes: 1 addition & 1 deletion packages/graphql-mesh/.meshrc.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { YamlConfig } from '@graphql-mesh/types'
import ConfigFromSwaggers from './utils/ConfigFromSwaggers'
import ConfigFromSwaggers from './utils/configFromSwaggers'
import { splDirectiveTypeDef } from 'directive-spl'
import { catchHTTPErrorDirectiveTypeDef } from './directives/catchHTTPError'
import { headersDirectiveTypeDef } from './directives/headers'
Expand Down
3 changes: 2 additions & 1 deletion packages/graphql-mesh/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"downloadswaggers": "NODE_TLS_REJECT_UNAUTHORIZED='0' sucrase-node ./scripts/download-sources.ts",
"postinstall": "patch-package",
"serve": "npm run build && sucrase-node serve.ts",
"start": "npm run downloadswaggers && mesh dev"
"start": "npm run downloadswaggers && mesh dev",
"test": "vitest"
},
"dependencies": {
"@graphql-mesh/cache-localforage": "^0.96.2",
Expand Down
289 changes: 289 additions & 0 deletions packages/graphql-mesh/tests/cases/configFromSwaggers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
import { describe, it, expect, beforeAll, vi } from 'vitest'
import ConfigFromSwaggers from '../../utils/configFromSwaggers'
import { globSync } from 'glob'
import { readFileSync } from 'node:fs'
import { Spec, Catalog } from '../../types'

// Mock dependencies
vi.mock('glob', () => ({ globSync: vi.fn() }))
vi.mock('node:fs', () => ({ readFileSync: vi.fn() }))

describe('ConfigFromSwaggers tests', () => {
let instance: ConfigFromSwaggers
let mockSpecs: Spec[]
let mockConfig: any

beforeAll(() => {
// Mock Swaggers
mockSpecs = [
{
openapi: '3.0.0',
info: {
title: 'getOwnerOfVehicleById',
version: '0.0.1'
},
paths: {
'/vehicle/{id}/owner': {
get: {
operationId: 'getOwnerOfVehicleById',
summary: 'Get the owner of a specific vehicle.',
responses: {
'200': {
description: '',
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/Person'
}
}
}
}
}
}
}
},
components: {
schemas: {
Person: {
type: 'object',
properties: {
id: {
type: 'integer'
}
}
}
}
}
},
{
openapi: '3.0.0',
info: {
title: 'getVehicles',
version: '0.0.1'
},
paths: {
'/vehicles': {
get: {
operationId: 'getVehicles',
summary: 'Get all vehicles.',
responses: {
'200': {
description: '',
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/Vehicles'
}
}
}
}
}
}
}
},
components: {
schemas: {
Vehicles: {
type: 'object',
properties: {
items: {
type: 'array',
items: {
$ref: '#/components/schemas/Vehicle'
}
}
}
},
Vehicle: {
type: 'object',
discriminator: {
propertyName: 'type',
mapping: {
Vehicle: '#/components/schemas/Vehicle',
Car: '#/components/schemas/Car',
Bike: '#/components/schemas/Bike'
}
},
properties: {
id: {
type: 'integer'
},
type: {
type: 'string'
}
}
},
Car: {
allOf: [
{
$ref: '#/components/schemas/Vehicle'
},
{
type: 'object',
properties: {
fuelType: {
type: 'string'
}
}
}
]
},
Bike: {
allOf: [
{
$ref: '#/components/schemas/Vehicle'
},
{
type: 'object',
properties: {
bikeType: {
type: 'string'
}
}
}
]
}
}
}
}
]
// Mock config
mockConfig = {
sources: [
{
name: 'getVehicles',
handler: {
openapi: {
operationHeaders: {}
}
}
},
{
name: 'getOwnerOfVehicleById',
handler: {
openapi: {
operationHeaders: {}
}
}
}
]
}
// Mock globSync
vi.mocked(globSync).mockReturnValue([
'mocks/getOwnerOfVehicleById.json',
'mocks/getVehicles.json'
])
// Mock readFileSync to return values of mockSpecs alternatively
const readFileSyncMock = (path: string, options?: { encoding?: string | null; flag?: string } | BufferEncoding) => {
let data;
if (path === 'mocks/getOwnerOfVehicleById.json') {
data = JSON.stringify(mockSpecs[0])
} else if (path === 'mocks/getVehicles.json') {
data = JSON.stringify(mockSpecs[1])
}

const encoding = typeof options === 'string' ? options : options?.encoding;
if (encoding === 'buffer' || !encoding) {
return Buffer.from(data ?? '');
}
return data;
};
vi.mocked(readFileSync).mockImplementation(readFileSyncMock);

vi.resetModules()

instance = new ConfigFromSwaggers()

instance.config = mockConfig
})

// Specs tests
it('should initialize swaggers and specs correctly', () => {
expect(instance.swaggers).toEqual([
'mocks/getOwnerOfVehicleById.json',
'mocks/getVehicles.json'
])
expect(instance.specs).toEqual(mockSpecs)
})

// Catalog test
it('should build the catalog correctly', () => {
const expectedCatalog: Catalog = {
'/vehicle/{id}/owner': {
operationIds: ['getOwnerOfVehicleById'],
type: 'Person',
swaggers: ['mocks/getOwnerOfVehicleById.json']
},
'/vehicles': {
operationIds: ['getVehicles'],
type: 'Vehicles',
swaggers: ['mocks/getVehicles.json']
}
}
expect(instance.catalog).toEqual(expectedCatalog)
})

// Test function to get available types
it('should return all the available types', () => {
const expectedTypes = ['Person', 'Vehicles', 'Vehicle', 'Car', 'Bike']
expect(instance.getAvailableTypes()).toEqual(expectedTypes)
})

// Test function to get interfaces with their children
it('should return interfaces with children correctly', () => {
const expectedInterfacesWithChildren: Record<string, string[]> = {
Vehicle: ['Car', 'Bike']
}
expect(instance.getInterfacesWithChildren()).toEqual(expectedInterfacesWithChildren)
})

// Test function to get OpenAPI sources
it('should get OpenAPI sources correctly', () => {
const expectedOpenApiSources = [
{
name: 'getOwnerOfVehicleById',
handler: {
openapi: {
source: 'mocks/getOwnerOfVehicleById.json',
endpoint: '{env.ENDPOINT}',
ignoreErrorResponses: true,
operationHeaders: {
Authorization: `{context.headers["authorization"]}`
}
}
},
transforms: undefined
},
{
name: 'getVehicles',
handler: {
openapi: {
source: 'mocks/getVehicles.json',
endpoint: '{env.ENDPOINT}',
ignoreErrorResponses: true,
operationHeaders: {
Authorization: `{context.headers["authorization"]}`
}
}
},
transforms: undefined
}
]
expect(instance.getOpenApiSources()).toEqual(expectedOpenApiSources)
})

// Test function to get non-OpenAPI sources
it('should get other sources correctly', () => {
const expectedOtherSources = []
expect(instance.getOtherSources()).toEqual(expectedOtherSources)
})

// Test function to get config from Swaggers
it('should return the complete mesh config from swaggers', () => {
const meshConfig = instance.getMeshConfigFromSwaggers()
expect(meshConfig.defaultConfig).toEqual(mockConfig)
expect(meshConfig.additionalTypeDefs).toContain('type LinkItem')
expect(meshConfig.additionalResolvers).toBeDefined()
expect(meshConfig.sources.length).toEqual(2)
})
})
Loading

0 comments on commit b7d8842

Please sign in to comment.