Skip to content

Commit

Permalink
✅ add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Mbaye THIAM committed Apr 16, 2024
1 parent b5c3a68 commit bffe680
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 31 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@ jobs:
- name: Setup services for testing purpose
run: export IMAGE_TAG=localhost:5000/test/graphql-mesh:latest && cd ./test/integration && docker compose up -d

- name: Inspect network
run: docker network inspect integration_default

- name: Set up Node.js
uses: actions/setup-node@v3
with:
Expand Down
4 changes: 2 additions & 2 deletions packages/graphql-mesh/utils/swaggers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,10 @@ export const generateTypeDefsAndResolversFromSwagger = (
root = { ...root, followLink: hateoasLink.href }
}

// @TODO: Fix type checking for interger params
if (paramsToSend.length) {
paramsToSend.forEach((param, i) => {
args[param] = root[param] || root[paramsFromLink[i]] || ''
// To avoid params validation error in case of missing params or type mismatch we set default value to '0'
args[param] = root[param] || root[paramsFromLink[i]] || '0'
})
}

Expand Down
2 changes: 1 addition & 1 deletion test/api/models/products.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type Product = {
function generateProducts() {
const _products: Product[] = []
for (let i = 1; i <= 50; i++) {
const supplierId = Math.floor(Math.random() * 10) + 1
const supplierId = (i % 10) + 1
const product: Product = {
id: i,
name: `Product ${i}`,
Expand Down
25 changes: 25 additions & 0 deletions test/integration/tests/cases/directive-spl.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { test, expect } from 'vitest'
import axios from 'axios'
import { url, headers } from '../config'

/* SPL filter */
const getTenFirstProductsQuery = /* GraphQL */ `
query getTenFirstProducts {
getProducts {
items @SPL(query: "id <= 10") {
name
id
price
supplierId
}
}
}
`

test('getTenFirstProducts with SPL filter query', async () => {
const response = await axios.post(url, { query: getTenFirstProductsQuery }, { headers })

Check failure on line 20 in test/integration/tests/cases/directive-spl.test.ts

View workflow job for this annotation

GitHub Actions / integration-tests (18.x)

cases/directive-spl.test.ts > getTenFirstProducts with SPL filter query

Error: socket hang up ❯ Function.AxiosError.from node_modules/axios/lib/core/AxiosError.js:89:14 ❯ RedirectableRequest.handleRequestError node_modules/axios/lib/adapters/http.js:610:25 ❯ RedirectableRequest.emit node:events:517:28 ❯ ClientRequest.eventHandlers.<computed> node_modules/follow-redirects/index.js:38:24 ❯ ClientRequest.emit node:events:517:28 ❯ Socket.socketOnEnd node:_http_client:525:9 ❯ Socket.emit node:events:529:35 ❯ Axios.request node_modules/axios/lib/core/Axios.js:45:41 ❯ cases/directive-spl.test.ts:20:20 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { code: 'ECONNRESET', config: { transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, adapter: [ 'xhr', 'http' ], transformRequest: [ 'Function<transformRequest>' ], transformResponse: [ 'Function<transformResponse>' ], timeout: +0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: { FormData: 'Function<FormData>', Blob: 'Function<Blob>' }, validateStatus: 'Function<validateStatus>', headers: { Accept: 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'User-Agent': 'axios/1.6.8', 'Content-Length': '187', 'Accept-Encoding': 'gzip, compress, deflate, br', constructor: 'Function<AxiosHeaders>', set: 'Function<set>', get: 'Function<get>', has: 'Function<has>', delete: 'Function<delete>', clear: 'Function<clear>', normalize: 'Function<normalize>', concat: 'Function<concat>', toJSON: 'Function<toJSON>', toString: 'Function<toString>', getContentType: 'Function<value>', setContentType: 'Function<value>', hasContentType: 'Function<value>', getContentLength: 'Function<value>', setContentLength: 'Function<value>', hasContentLength: 'Function<value>', getAccept: 'Function<value>', setAccept: 'Function<value>', hasAccept: 'Function<value>', getAcceptEncoding: 'Function<value>', setAcceptEncoding: 'Function<value>', hasAcceptEncoding: 'Function<value>', getUserAgent: 'Function<value>', setUserAgent: 'Function<value>', hasUserAgent: 'Function<value>', getAuthorization: 'Function<value>', setAuthorization: 'Function<value>', hasAuthorization: 'Function<value>' }, method: 'post', url: 'http://0.0.0.0:45538/graphql', data: '{"query":"\n query getTenFirstProducts {\n getProducts {\n items @spl(query: \"id <= 10\") {\n name\n id\n price\n supplierId\n }\n }\n }\n"}' }, request: { _writableState: { objectMode: false, highWaterMark: 16384, finalCalled: false, needDrain: false, ending: false, ended: false, finished: false, destroyed: false, decodeStrings: true, defaultEncoding: 'utf8', length: +0, writing: false, corked: +0, sync: true, bufferProcessing: false, onwrite: 'Function<bound onwrite>', writecb: null, writelen: +0, afterWriteTickInfo: null, buffered: [], bufferedIndex: +0, allBuffers: true, allNoop: true, pendingcb: +0, constructed: true, prefinished: false, errorEmitted: false, emitClose: true, autoDestroy: true, errored: null, closed: false, closeEmitted: false, constructor: 'Function<WritableState>', getBuffer: 'Function<getBuffer>', bufferedRequestCount: +0 }, _events: { response: 'Function<handleResponse>', error: 'Function<handleRequestError>', socket: 'Function<handleRequestSocket>' }, _eventsCount: 3, _maxListeners: undefined, _options: { maxRedirects: 21, maxBodyLength: Infinity, protocol: 'http:', path: '/graphql', method: 'POST', headers: { Accept: 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'User-Agent': 'axios/1.6.8', 'Content-Length': '187', 'Accept-Encoding': 'gzip, compress, deflate, br' }, agents: { http: undefined, https: undefined }, auth: undefined, family: undefined, beforeRedirect: 'Function<dispatchBeforeRedirect>', beforeRedirects: { proxy: 'Function<beforeRedirect>' }, hostname: '0.0.0.0', port: '45538', agent: undefined, nativeProtocols: { 'http:': { _connectionListener: 'Function<connectionListener>', METHODS: [ 'ACL', 'BIND', 'CHECKOUT', 'CONNECT', 'COPY', 'DELETE', 'GET', 'HEAD', 'LINK', 'LOCK', 'M-SEARCH', 'MERGE', 'MKACTIVITY', 'M

const result = response.data
expect(response.status).toBe(200)
expect(result.data.getProducts.items.length).toEqual(10)
})
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { test, expect } from 'vitest'
import axios from 'axios'

const url = 'http://0.0.0.0:45538/graphql'
const headers = { 'Content-Type': 'application/json' }
import { url, headers } from '../config'

/* Get all products */
const getAllProductsQuery = /* GraphQL */ `
Expand All @@ -28,46 +26,55 @@ test('getAllProducts query', async () => {
expect(result.data.getProducts.items.length).toEqual(50)
})

/* SPL filter */
const getTenFirstProductsQuery = /* GraphQL */ `
query getTenFirstProducts {
getProducts {
items @SPL(query: "id <= 10") {
/* Hateoas link */
const getProductAndSupplierInfo = /* GraphQL */ `
query getProductAndSupplierInfo {
getProductById(id: 1) {
id
name
price
supplier {
name
id
price
supplierId
}
}
}
`

test('getTenFirstProducts with SPL filter query', async () => {
const response = await axios.post(url, { query: getTenFirstProductsQuery }, { headers })
test('Follow hateoas link to get Suppier info', async () => {
const response = await axios.post(url, { query: getProductAndSupplierInfo }, { headers })

Check failure on line 45 in test/integration/tests/cases/graphql-mesh.test.ts

View workflow job for this annotation

GitHub Actions / integration-tests (18.x)

cases/graphql-mesh.test.ts > Follow hateoas link to get Suppier info

Error: socket hang up ❯ Function.AxiosError.from node_modules/axios/lib/core/AxiosError.js:89:14 ❯ RedirectableRequest.handleRequestError node_modules/axios/lib/adapters/http.js:610:25 ❯ RedirectableRequest.emit node:events:517:28 ❯ ClientRequest.eventHandlers.<computed> node_modules/follow-redirects/index.js:38:24 ❯ ClientRequest.emit node:events:517:28 ❯ Socket.socketOnEnd node:_http_client:525:9 ❯ Socket.emit node:events:529:35 ❯ Axios.request node_modules/axios/lib/core/Axios.js:45:41 ❯ cases/graphql-mesh.test.ts:45:20 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { code: 'ECONNRESET', config: { transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, adapter: [ 'xhr', 'http' ], transformRequest: [ 'Function<transformRequest>' ], transformResponse: [ 'Function<transformResponse>' ], timeout: +0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: { FormData: 'Function<FormData>', Blob: 'Function<Blob>' }, validateStatus: 'Function<validateStatus>', headers: { Accept: 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'User-Agent': 'axios/1.6.8', 'Content-Length': '180', 'Accept-Encoding': 'gzip, compress, deflate, br', constructor: 'Function<AxiosHeaders>', set: 'Function<set>', get: 'Function<get>', has: 'Function<has>', delete: 'Function<delete>', clear: 'Function<clear>', normalize: 'Function<normalize>', concat: 'Function<concat>', toJSON: 'Function<toJSON>', toString: 'Function<toString>', getContentType: 'Function<value>', setContentType: 'Function<value>', hasContentType: 'Function<value>', getContentLength: 'Function<value>', setContentLength: 'Function<value>', hasContentLength: 'Function<value>', getAccept: 'Function<value>', setAccept: 'Function<value>', hasAccept: 'Function<value>', getAcceptEncoding: 'Function<value>', setAcceptEncoding: 'Function<value>', hasAcceptEncoding: 'Function<value>', getUserAgent: 'Function<value>', setUserAgent: 'Function<value>', hasUserAgent: 'Function<value>', getAuthorization: 'Function<value>', setAuthorization: 'Function<value>', hasAuthorization: 'Function<value>' }, method: 'post', url: 'http://0.0.0.0:45538/graphql', data: '{"query":"\n query getProductAndSupplierInfo {\n getProductById(id: 1) {\n id\n name\n price\n supplier {\n name\n id\n }\n }\n }\n"}' }, request: { _writableState: { objectMode: false, highWaterMark: 16384, finalCalled: false, needDrain: false, ending: false, ended: false, finished: false, destroyed: false, decodeStrings: true, defaultEncoding: 'utf8', length: +0, writing: false, corked: +0, sync: true, bufferProcessing: false, onwrite: 'Function<bound onwrite>', writecb: null, writelen: +0, afterWriteTickInfo: null, buffered: [], bufferedIndex: +0, allBuffers: true, allNoop: true, pendingcb: +0, constructed: true, prefinished: false, errorEmitted: false, emitClose: true, autoDestroy: true, errored: null, closed: false, closeEmitted: false, constructor: 'Function<WritableState>', getBuffer: 'Function<getBuffer>', bufferedRequestCount: +0 }, _events: { response: 'Function<handleResponse>', error: 'Function<handleRequestError>', socket: 'Function<handleRequestSocket>' }, _eventsCount: 3, _maxListeners: undefined, _options: { maxRedirects: 21, maxBodyLength: Infinity, protocol: 'http:', path: '/graphql', method: 'POST', headers: { Accept: 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'User-Agent': 'axios/1.6.8', 'Content-Length': '180', 'Accept-Encoding': 'gzip, compress, deflate, br' }, agents: { http: undefined, https: undefined }, auth: undefined, family: undefined, beforeRedirect: 'Function<dispatchBeforeRedirect>', beforeRedirects: { proxy: 'Function<beforeRedirect>' }, hostname: '0.0.0.0', port: '45538', agent: undefined, nativeProtocols: { 'http:': { _connectionListener: 'Function<connectionListener>', METHODS: [ 'ACL', 'BIND', 'CHECKOUT', 'CONNECT', 'COPY', 'DELETE', 'GET', 'HEAD', 'LINK', 'LOCK', 'M-SEARCH', 'MERGE', 'MKACTIVITY', 'MKCALENDA

const result = response.data
expect(response.status).toBe(200)
expect(result.data.getProducts.items.length).toEqual(10)
expect(result.data.getProductById.supplier.name).contains('Supplier 3')
})

/* Hateoas link */
const getProductAndSupplierInfo = /* GraphQL */ `
query getProductAndSupplierInfo {
/* Linklist property */

const getProductwithLinkList = /* GraphQL */ `
query getProductWithLinkList {
getProductById(id: 1) {
id
name
price
supplier {
name
id
supplierId
_linksList {
rel
href
}
}
}
`

test('Follow hateoas link to get Suppier info', async () => {
const response = await axios.post(url, { query: getProductAndSupplierInfo }, { headers })
const response = await axios.post(url, { query: getProductwithLinkList }, { headers })

Check failure on line 66 in test/integration/tests/cases/graphql-mesh.test.ts

View workflow job for this annotation

GitHub Actions / integration-tests (18.x)

cases/graphql-mesh.test.ts > Follow hateoas link to get Suppier info

Error: socket hang up ❯ Function.AxiosError.from node_modules/axios/lib/core/AxiosError.js:89:14 ❯ RedirectableRequest.handleRequestError node_modules/axios/lib/adapters/http.js:610:25 ❯ RedirectableRequest.emit node:events:517:28 ❯ ClientRequest.eventHandlers.<computed> node_modules/follow-redirects/index.js:38:24 ❯ ClientRequest.emit node:events:517:28 ❯ Socket.socketOnEnd node:_http_client:525:9 ❯ Socket.emit node:events:529:35 ❯ Axios.request node_modules/axios/lib/core/Axios.js:45:41 ❯ cases/graphql-mesh.test.ts:66:20 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { code: 'ECONNRESET', config: { transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, adapter: [ 'xhr', 'http' ], transformRequest: [ 'Function<transformRequest>' ], transformResponse: [ 'Function<transformResponse>' ], timeout: +0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: { FormData: 'Function<FormData>', Blob: 'Function<Blob>' }, validateStatus: 'Function<validateStatus>', headers: { Accept: 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'User-Agent': 'axios/1.6.8', 'Content-Length': '163', 'Accept-Encoding': 'gzip, compress, deflate, br', constructor: 'Function<AxiosHeaders>', set: 'Function<set>', get: 'Function<get>', has: 'Function<has>', delete: 'Function<delete>', clear: 'Function<clear>', normalize: 'Function<normalize>', concat: 'Function<concat>', toJSON: 'Function<toJSON>', toString: 'Function<toString>', getContentType: 'Function<value>', setContentType: 'Function<value>', hasContentType: 'Function<value>', getContentLength: 'Function<value>', setContentLength: 'Function<value>', hasContentLength: 'Function<value>', getAccept: 'Function<value>', setAccept: 'Function<value>', hasAccept: 'Function<value>', getAcceptEncoding: 'Function<value>', setAcceptEncoding: 'Function<value>', hasAcceptEncoding: 'Function<value>', getUserAgent: 'Function<value>', setUserAgent: 'Function<value>', hasUserAgent: 'Function<value>', getAuthorization: 'Function<value>', setAuthorization: 'Function<value>', hasAuthorization: 'Function<value>' }, method: 'post', url: 'http://0.0.0.0:45538/graphql', data: '{"query":"\n query getProductWithLinkList {\n getProductById(id: 1) {\n supplierId\n _linksList {\n rel\n href\n }\n }\n }\n"}' }, request: { _writableState: { objectMode: false, highWaterMark: 16384, finalCalled: false, needDrain: false, ending: false, ended: false, finished: false, destroyed: false, decodeStrings: true, defaultEncoding: 'utf8', length: +0, writing: false, corked: +0, sync: true, bufferProcessing: false, onwrite: 'Function<bound onwrite>', writecb: null, writelen: +0, afterWriteTickInfo: null, buffered: [], bufferedIndex: +0, allBuffers: true, allNoop: true, pendingcb: +0, constructed: true, prefinished: false, errorEmitted: false, emitClose: true, autoDestroy: true, errored: null, closed: false, closeEmitted: false, constructor: 'Function<WritableState>', getBuffer: 'Function<getBuffer>', bufferedRequestCount: +0 }, _events: { response: 'Function<handleResponse>', error: 'Function<handleRequestError>', socket: 'Function<handleRequestSocket>' }, _eventsCount: 3, _maxListeners: undefined, _options: { maxRedirects: 21, maxBodyLength: Infinity, protocol: 'http:', path: '/graphql', method: 'POST', headers: { Accept: 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'User-Agent': 'axios/1.6.8', 'Content-Length': '163', 'Accept-Encoding': 'gzip, compress, deflate, br' }, agents: { http: undefined, https: undefined }, auth: undefined, family: undefined, beforeRedirect: 'Function<dispatchBeforeRedirect>', beforeRedirects: { proxy: 'Function<beforeRedirect>' }, hostname: '0.0.0.0', port: '45538', agent: undefined, nativeProtocols: { 'http:': { _connectionListener: 'Function<connectionListener>', METHODS: [ 'ACL', 'BIND', 'CHECKOUT', 'CONNECT', 'COPY', 'DELETE', 'GET', 'HEAD', 'LINK', 'LOCK', 'M-SEARCH', 'MERGE', 'MKACTIVITY', 'MKCALENDAR', 'MKCOL', 'MOV

const result = response.data
expect(result.data.getProductById.supplier.name).contains('Supplier')
expect(result.data.getProductById._linksList.length).toEqual(2)
expect(result.data.getProductById._linksList).toEqual([
{
rel: 'self',
href: '/products/1'
},
{
rel: 'supplier',
href: '/suppliers/3'
}
])
})
22 changes: 22 additions & 0 deletions test/integration/tests/cases/inject-additionnal-transforms.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { test, expect } from 'vitest'
import axios from 'axios'
import { url, headers } from '../config'

/* Get all products */
const getProductById = /* GraphQL */ `
query getProduct {
getProductById(id: 1) {
name @lower
price
supplierId
}
}
`

test('Injection lower transform', async () => {
const response = await axios.post(url, { query: getProductById }, { headers })

const result = response.data
expect(result).toHaveProperty('data')
expect(result.data.getProductById.name).toEqual('product 1')
})
20 changes: 20 additions & 0 deletions test/integration/tests/cases/plugins.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { test, expect } from 'vitest'
import axios from 'axios'
import { url, headers } from '../config'

/* Get all products */
const getProductById = /* GraphQL */ `
query getProduct {
getProductById(id: 1) {
name
price
supplierId
}
}
`

test('Server timing plugin', async () => {
const response = await axios.post(url, { query: getProductById }, { headers })
const serverTiming = response.headers['server-timing']
expect(serverTiming).contains('getProductById;desc="getProductById (Products)";dur')
})
3 changes: 3 additions & 0 deletions test/integration/tests/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const url = 'http://0.0.0.0:45538/graphql'
// export const url = 'http://0.0.0.0:4000/graphql'
export const headers = { 'Content-Type': 'application/json' }

0 comments on commit bffe680

Please sign in to comment.