Skip to content

Commit

Permalink
refactor: lint
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonkuhrt committed Apr 5, 2023
1 parent e596527 commit b563ad5
Show file tree
Hide file tree
Showing 12 changed files with 110 additions and 114 deletions.
2 changes: 1 addition & 1 deletion examples/cookie-support-for-node.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
;(global as any).fetch = require(`fetch-cookie/node-fetch`)(require(`node-fetch`))
;(global as any).fetch = require(`fetch-cookie/node-fetch`)(require(`node-fetch`)) //eslint-disable-line

import { gql, GraphQLClient } from '../src/index.js'

Expand Down
3 changes: 1 addition & 2 deletions examples/typed-document-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ import { parse } from 'graphql'
}
`)

const variables = {}

const data = await client.request({ document: query })
// const variables = {}
// const data = await client.request({ document: query, variables: { a: 1 } })

console.log(data.greetings)
Expand Down
11 changes: 6 additions & 5 deletions src/createRequestBody.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import FormDataNode from 'form-data'
* Duck type if NodeJS stream
* https://github.com/sindresorhus/is-stream/blob/3750505b0727f6df54324784fe369365ef78841e/index.js#L3
*/
const isExtractableFileEnhanced = (value: any): value is ExtractableFile | { pipe: Function } =>
const isExtractableFileEnhanced = (value: unknown): value is ExtractableFile | { pipe: () => unknown } =>
isExtractableFile(value) ||
(value !== null && typeof value === `object` && typeof value.pipe === `function`)
(typeof value === `object` && value !== null && `pipe` in value && typeof value.pipe === `function`)

/**
* Returns Multipart Form if body contains files
Expand All @@ -23,6 +23,7 @@ const createRequestBody = (
operationName?: string,
jsonSerializer = defaultJsonSerializer
): string | FormData => {
// eslint-disable-next-line
const { clone, files } = extractFiles({ query, variables, operationName }, ``, isExtractableFileEnhanced)

if (files.size === 0) {
Expand All @@ -36,9 +37,9 @@ const createRequestBody = (

// Batch support
const payload = query.reduce<{ query: string; variables: Variables | undefined }[]>(
(accu, currentQuery, index) => {
accu.push({ query: currentQuery, variables: variables ? variables[index] : undefined })
return accu
(acc, currentQuery, index) => {
acc.push({ query: currentQuery, variables: variables ? variables[index] : undefined })
return acc
},
[]
)
Expand Down
1 change: 1 addition & 0 deletions src/graphql-ws.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable */
import { resolveRequestDocument } from './resolveRequestDocument.js'
import type { RequestDocument, Variables } from './types.js'
import { ClientError } from './types.js'
Expand Down
39 changes: 14 additions & 25 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,10 +316,7 @@ export class GraphQLClient {
// prettier-ignore
batchRequests<T extends BatchResult, V extends Variables = Variables>(options: BatchRequestsOptions<V>): Promise<T>
// prettier-ignore
batchRequests<T extends BatchResult, V extends Variables = Variables>(
documentsOrOptions: BatchRequestDocument<V>[] | BatchRequestsOptions<V>,
requestHeaders?: GraphQLClientRequestHeaders
): Promise<T> {
batchRequests<T extends BatchResult, V extends Variables = Variables>(documentsOrOptions: BatchRequestDocument<V>[] | BatchRequestsOptions<V>, requestHeaders?: GraphQLClientRequestHeaders): Promise<T> {
const batchRequestOptions = parseBatchRequestArgs<V>(documentsOrOptions, requestHeaders)
const { headers, ...fetchOptions } = this.requestConfig

Expand Down Expand Up @@ -374,7 +371,7 @@ export class GraphQLClient {

if (headers) {
// todo what if headers is in nested array form... ?
//@ts-ignore
//@ts-expect-error todo
headers[key] = value
} else {
this.requestConfig.headers = { [key]: value }
Expand Down Expand Up @@ -422,7 +419,7 @@ const makeRequest = async <T = unknown, V extends Variables = Variables>(params:

if (response.ok && successfullyPassedErrorPolicy && successfullyReceivedData) {
// @ts-expect-error TODO fixme
const { errors, ...rest } = Array.isArray(result) ? result : result
const { errors: _, ...rest } = Array.isArray(result) ? result : result
const data = fetchOptions.errorPolicy === `ignore` ? rest : result
const dataEnvelope = isBatchingQuery ? { data } : data

Expand Down Expand Up @@ -517,22 +514,13 @@ export const rawRequest: RawRequest = async <T, V extends Variables>(
* await request('https://foo.bar/graphql', gql`...`)
* ```
*/
export async function request<T, V extends Variables = Variables>(
url: string,
// @ts-ignore
document: RequestDocument | TypedDocumentNode<T, V>,
...variablesAndRequestHeaders: VariablesAndRequestHeadersArgs<V>
): Promise<T>
export async function request<T, V extends Variables = Variables>(
options: RequestExtendedOptions<V, T>
): Promise<T>
export async function request<T, V extends Variables = Variables>(
urlOrOptions: string | RequestExtendedOptions<V, T>,
// @ts-ignore
document?: RequestDocument | TypedDocumentNode<T, V>,
...variablesAndRequestHeaders: VariablesAndRequestHeadersArgs<V>
): Promise<T> {
// @ts-ignore
// prettier-ignore
export async function request<T, V extends Variables = Variables>(url: string, document: RequestDocument | TypedDocumentNode<T, V>, ...variablesAndRequestHeaders: VariablesAndRequestHeadersArgs<V>): Promise<T>
// prettier-ignore
export async function request<T, V extends Variables = Variables>(options: RequestExtendedOptions<V, T>): Promise<T>
// prettier-ignore
// eslint-disable-next-line
export async function request<T, V extends Variables = Variables>(urlOrOptions: string | RequestExtendedOptions<V, T>, document?: RequestDocument | TypedDocumentNode<T, V>, ...variablesAndRequestHeaders: VariablesAndRequestHeadersArgs<V>): Promise<T> {
const requestOptions = parseRequestExtendedArgs<V>(urlOrOptions, document, ...variablesAndRequestHeaders)
const client = new GraphQLClient(requestOptions.url)
return client.request<T, V>({
Expand Down Expand Up @@ -648,18 +636,19 @@ const callOrIdentity = <T>(value: MaybeFunction<T>) => {
* Convenience passthrough template tag to get the benefits of tooling for the gql template tag. This does not actually parse the input into a GraphQL DocumentNode like graphql-tag package does. It just returns the string with any variables given interpolated. Can save you a bit of performance and having to install another package.
*
* @example
*
* ```
* import { gql } from 'graphql-request'
*
* await request('https://foo.bar/graphql', gql`...`)
* ```
*
* @remarks
*
* Several tools in the Node GraphQL ecosystem are hardcoded to specially treat any template tag named "gql". For example see this prettier issue: https://github.com/prettier/prettier/issues/4360. Using this template tag has no runtime effect beyond variable interpolation.
*/
export const gql = (chunks: TemplateStringsArray, ...variables: any[]): string => {
export const gql = (chunks: TemplateStringsArray, ...variables: unknown[]): string => {
return chunks.reduce(
(accumulator, chunk, index) => `${accumulator}${chunk}${index in variables ? variables[index] : ``}`,
(acc, chunk, index) => `${acc}${chunk}${index in variables ? String(variables[index]) : ``}`,
``
)
}
Expand Down
9 changes: 6 additions & 3 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import type { RemoveIndex } from './helpers.js'
import type { TypedDocumentNode } from '@graphql-typed-document-node/core'
import type { fetch } from 'cross-fetch'
import type { GraphQLError } from 'graphql/error/GraphQLError.js'
import type { DocumentNode } from 'graphql/language/ast.js'

export type Fetch = typeof fetch

/**
* 'None' will throw whenever the response contains errors
*
Expand All @@ -13,8 +16,8 @@ import type { DocumentNode } from 'graphql/language/ast.js'
export type ErrorPolicy = 'none' | 'ignore' | 'all'

export interface JsonSerializer {
stringify(obj: any): string
parse(obj: string): unknown
stringify: (obj: any) => string
parse: (obj: string) => unknown
}

export interface AdditionalRequestOptions {
Expand Down Expand Up @@ -89,7 +92,7 @@ export interface GraphQLClientResponse<T> {
export type HTTPMethodInput = 'GET' | 'POST' | 'get' | 'post'

export interface RequestConfig extends Omit<RequestInit, 'headers' | 'method'>, AdditionalRequestOptions {
fetch?: any
fetch?: Fetch
method?: HTTPMethodInput
headers?: MaybeFunction<GraphQLClientRequestHeaders>
requestMiddleware?: RequestMiddleware
Expand Down
55 changes: 32 additions & 23 deletions tests/__helpers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { ApolloServerExpressConfig } from 'apollo-server-express'
import { ApolloServer } from 'apollo-server-express'
import body from 'body-parser'
import type { Application, Request } from 'express'
Expand Down Expand Up @@ -45,7 +46,9 @@ type MockResult<Spec extends MockSpec | MockSpecBatch = MockSpec> = {
}[]
}

export function setupMockServer<T extends MockSpec | MockSpecBatch = MockSpec>(delay?: number): Context<T> {
export const setupMockServer = <T extends MockSpec | MockSpecBatch = MockSpec>(
delay?: number
): Context<T> => {
const ctx = {} as Context<T>
beforeAll(async () => {
const port = await getPort()
Expand All @@ -60,23 +63,24 @@ export function setupMockServer<T extends MockSpec | MockSpecBatch = MockSpec>(d
ctx.url = `http://localhost:${port}`
ctx.res = (spec?: T): MockResult<T> => {
const requests: CapturedRequest[] = []
ctx.server.use(`*`, async function mock(req, res) {
if (delay) {
await sleep(delay)
}

req.headers.host = `DYNAMIC`
requests.push({
method: req.method,
headers: req.headers,
body: req.body,
})
if (spec?.headers) {
Object.entries(spec.headers).forEach(([name, value]) => {
res.setHeader(name, value)
// eslint-disable-next-line
ctx.server.use(`*`, function mock(req, res) {
void new Promise((res) => {
delay ? setTimeout(res, delay) : res(undefined)
}).then(() => {
req.headers.host = `DYNAMIC`
requests.push({
method: req.method,
headers: req.headers,
body: req.body, // eslint-disable-line
})
}
res.send(spec?.body ?? { data: {} })
if (spec?.headers) {
Object.entries(spec.headers).forEach(([name, value]) => {
res.setHeader(name, value)
})
}
res.send(spec?.body ?? { data: {} })
})
})

return { spec, requests: requests } as MockResult<T>
Expand All @@ -85,7 +89,9 @@ export function setupMockServer<T extends MockSpec | MockSpecBatch = MockSpec>(d

afterEach(() => {
// https://stackoverflow.com/questions/10378690/remove-route-mappings-in-nodejs-express/28369539#28369539
// eslint-disable-next-line
ctx.server._router.stack.forEach((item: any, i: number) => {
// eslint-disable-next-line
if (item.name === `mock`) ctx.server._router.stack.splice(i, 1)
})
})
Expand All @@ -101,15 +107,18 @@ export function setupMockServer<T extends MockSpec | MockSpecBatch = MockSpec>(d
return ctx
}

type ApolloServerContextOptions = { typeDefs: string; resolvers: any }
type ApolloServerContextOptions = {
typeDefs: string
resolvers: ApolloServerExpressConfig['resolvers']
}

export async function startApolloServer({ typeDefs, resolvers }: ApolloServerContextOptions) {
export const startApolloServer = async ({ typeDefs, resolvers }: ApolloServerContextOptions) => {
const app = express()

const apolloServer = new ApolloServer({ typeDefs, resolvers })

await apolloServer.start()
apolloServer.applyMiddleware({ app: app as any })
apolloServer.applyMiddleware({ app })

let server: Server

Expand All @@ -120,8 +129,8 @@ export async function startApolloServer({ typeDefs, resolvers }: ApolloServerCon
return server!
}

export function createApolloServerContext({ typeDefs, resolvers }: ApolloServerContextOptions) {
const ctx: { url: string; server: Server } = {} as any
export const createApolloServerContext = ({ typeDefs, resolvers }: ApolloServerContextOptions) => {
const ctx: { url: string; server: Server } = {} as any // eslint-disable-line

beforeEach(async () => {
ctx.server = await startApolloServer({ typeDefs, resolvers })
Expand All @@ -140,7 +149,7 @@ export function createApolloServerContext({ typeDefs, resolvers }: ApolloServerC
return ctx
}

export function sleep(timeout: number): Promise<void> {
export const sleep = (timeout: number): Promise<void> => {
return new Promise((resolve) => {
setTimeout(resolve, timeout)
})
Expand Down
5 changes: 2 additions & 3 deletions tests/custom-fetch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ const ctx = setupMockServer()

test(`with custom fetch`, async () => {
let touched = false
// wrap fetch in a custom method
const customFetch = function (input: RequestInfo, init?: RequestInit) {
const customFetch = (input: RequestInfo | URL, init?: RequestInit) => {
touched = true
return fetch(input, init)
}
const client = new GraphQLClient(ctx.url, { fetch: customFetch })
const mock = ctx.res()
ctx.res()
await client.request(`{ me { id } }`)
expect(touched).toEqual(true)
})
4 changes: 2 additions & 2 deletions tests/errorPolicy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ test(`should throw error when error policy not set`, async () => {
},
})

expect(async () => await new GraphQLClient(ctx.url).rawRequest(`x`)).rejects.toThrow(`GraphQL Error`)
await expect(() => new GraphQLClient(ctx.url).rawRequest(`x`)).rejects.toThrow(`GraphQL Error`)
})

test(`should throw error when error policy set to "none"`, async () => {
Expand All @@ -32,7 +32,7 @@ test(`should throw error when error policy set to "none"`, async () => {
},
})

expect(async () => await new GraphQLClient(ctx.url).rawRequest(`x`)).rejects.toThrow(`GraphQL Error`)
await expect(() => new GraphQLClient(ctx.url).rawRequest(`x`)).rejects.toThrow(`GraphQL Error`)
})

test(`should not throw error when error policy set to "ignore" and return only data`, async () => {
Expand Down
Loading

0 comments on commit b563ad5

Please sign in to comment.