@avantstay/graphql-ts-client 10.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,69 @@
1
+ type Maybe<T> = null | undefined | T;
2
+ type Defined<T> = Exclude<T, undefined>;
3
+ type ResponseData = {
4
+ data: any;
5
+ warnings: any;
6
+ headers: any;
7
+ status?: number;
8
+ errors: {
9
+ message: string;
10
+ }[];
11
+ };
12
+ type ResponseListenerInfo = {
13
+ queryName: string;
14
+ query: string;
15
+ variables: any;
16
+ response: ResponseData;
17
+ };
18
+ type IResponseListener = (info: ResponseListenerInfo) => void | Promise<void>;
19
+ type ArrayElement<ArrayType extends readonly unknown[]> = ArrayType extends readonly (infer ElementType)[] ? ElementType : never;
20
+ type Projection<Selection, Base, E = never> = Base extends Array<any> ? ArrayElement<Base> extends Date | string | number | boolean | null | undefined | E ? ArrayElement<Base>[] : Projection<Defined<Selection>, ArrayElement<Base>, E>[] : Base extends Date | string | number | boolean | null | E ? Selection extends undefined ? Base | undefined : Base : {
21
+ [k in keyof Selection & keyof Base]: Selection[k] extends boolean ? Base[k] : Base[k] extends Array<infer A> ? Projection<Defined<Selection[k]>, A, E>[] : Projection<Defined<Selection[k]>, Base[k], E>;
22
+ };
23
+ type Unpacked<T> = T extends (infer U)[] ? U : T extends (...args: any[]) => infer U ? U : T extends Promise<infer U> ? U : T;
24
+ type Replacement<M extends [any, any], T> = M extends any ? ([T] extends [M[0]] ? M[1] : never) : never;
25
+ type DeepReplace<T, Ignore, M extends [any, any]> = {
26
+ [P in keyof T]: T[P] extends M[0] ? T[P] extends Ignore ? T[P] extends object ? DeepReplace<T[P], Ignore, M> : T[P] : Replacement<M, T[P]> : T[P] extends object ? DeepReplace<T[P], Ignore, M> : T[P];
27
+ };
28
+ type RawEndpoint<I, O, E> = <S extends I>(jsonQuery?: S) => Promise<{
29
+ data: Projection<S, O, E>;
30
+ errors: any[];
31
+ warnings: any[];
32
+ headers: any;
33
+ status: any;
34
+ }>;
35
+ type JsonOutput<O, ToBeIgnored> = DeepReplace<O, ToBeIgnored, [string | Date, string]>;
36
+ type Endpoint<I, O, E> = (<S extends I>(jsonQuery?: S) => Promise<Projection<S, JsonOutput<O, E>, E>>) & {
37
+ memo: <S extends I>(jsonQuery?: S) => Promise<Projection<S, JsonOutput<O, E>, E>>;
38
+ memoRaw: RawEndpoint<I, JsonOutput<O, E>, E>;
39
+ raw: RawEndpoint<I, JsonOutput<O, E>, E>;
40
+ };
41
+ type ClientConfig = {
42
+ url: string;
43
+ headers: {
44
+ [key: string]: string;
45
+ };
46
+ retryConfig: {
47
+ max: number;
48
+ waitBeforeRetry?: number;
49
+ before: IResponseListener;
50
+ };
51
+ };
52
+ type LogInfo = {
53
+ query: string;
54
+ variables: any;
55
+ formatGraphQL: any;
56
+ kind: string;
57
+ queryName: string;
58
+ response?: any;
59
+ error?: Error;
60
+ duration: number;
61
+ };
62
+ declare class GraphQLClientError extends Error {
63
+ responseData: ResponseData;
64
+ constructor(responseData: ResponseData);
65
+ get message(): string;
66
+ get response(): ResponseData;
67
+ }
68
+
69
+ export { ClientConfig as C, Defined as D, Endpoint as E, GraphQLClientError as G, IResponseListener as I, JsonOutput as J, LogInfo as L, Maybe as M, Projection as P, ResponseData as R, Unpacked as U, ResponseListenerInfo as a, Replacement as b, DeepReplace as c, RawEndpoint as d };
package/package.json ADDED
@@ -0,0 +1,85 @@
1
+ {
2
+ "name": "@avantstay/graphql-ts-client",
3
+ "version": "10.5.0",
4
+ "description": "GraphQL Typescript Client Generator",
5
+ "author": "Wellington Guimaraes",
6
+ "license": "MIT",
7
+ "main": "dist/index.js",
8
+ "typings": "dist/index.d.ts",
9
+ "scripts": {
10
+ "build": "tsup src/index.ts src/endpoint.ts --dts",
11
+ "test": "cross-env GQL_CLIENT_DIST_PATH='.' jest --watch",
12
+ "prepublishOnly": "yarn build"
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "src"
17
+ ],
18
+ "engines": {
19
+ "node": ">=12"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/avantstay/graphql-ts-client/issues"
23
+ },
24
+ "homepage": "https://github.com/avantstay/graphql-ts-client#readme",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/avantstay/graphql-ts-client.git"
28
+ },
29
+ "peerDependencies": {},
30
+ "prettier": {
31
+ "trailingComma": "es5",
32
+ "tabWidth": 2,
33
+ "proseWrap": "always",
34
+ "bracketSpacing": true,
35
+ "jsxBracketSameLine": false,
36
+ "semi": false,
37
+ "singleQuote": true,
38
+ "arrowParens": "avoid",
39
+ "endOfLine": "lf",
40
+ "printWidth": 130,
41
+ "htmlWhitespaceSensitivity": "ignore",
42
+ "jsxSingleQuote": false
43
+ },
44
+ "module": "dist/graphql-ts-client.esm.js",
45
+ "size-limit": [
46
+ {
47
+ "path": "dist/graphql-ts-client.cjs.production.min.js",
48
+ "limit": "10 KB"
49
+ },
50
+ {
51
+ "path": "dist/graphql-ts-client.esm.js",
52
+ "limit": "10 KB"
53
+ }
54
+ ],
55
+ "dependencies": {
56
+ "@types/md5": "^2.3.2",
57
+ "axios": "^1.4.0",
58
+ "axios-retry": "^3.5.1",
59
+ "case": "^1.6.3",
60
+ "esbuild": "^0.18.16",
61
+ "graphql": "^16.7.1",
62
+ "lodash": "^4.17.21",
63
+ "md5": "^2.3.0",
64
+ "moize": "^6.1.6",
65
+ "prettier": "^2.8.8",
66
+ "ts-essentials": "^8.1.0"
67
+ },
68
+ "devDependencies": {
69
+ "@babel/preset-env": "^7.22.9",
70
+ "@babel/preset-typescript": "^7.22.5",
71
+ "@jest/globals": "^29.6.1",
72
+ "@types/graphql": "^14.5.0",
73
+ "@types/jest": "^29.5.3",
74
+ "@types/lodash": "^4.14.195",
75
+ "@types/node": "^20.4.5",
76
+ "@types/prettier": "^2.7.3",
77
+ "apollo-server": "^3.12.0",
78
+ "cross-env": "^7.0.3",
79
+ "jest": "^29.6.1",
80
+ "ts-node": "^10.9.1",
81
+ "tsup": "^7.1.0",
82
+ "typescript": "^5.1.6",
83
+ "@swc/core": "^1.3.71"
84
+ }
85
+ }
@@ -0,0 +1,24 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`GraphQLRequest Should request have proper structure 1`] = `
4
+ Arguments [
5
+ "https://whatever.com",
6
+ {
7
+ "operationName": "sampleQueryName",
8
+ "query": "sampleQuery",
9
+ "variables": {
10
+ "bar": "foo",
11
+ "foo": "bar",
12
+ },
13
+ },
14
+ {
15
+ "headers": {
16
+ "Content-Type": "application/json",
17
+ },
18
+ "params": {
19
+ "_q": "sampleQueryName",
20
+ },
21
+ "validateStatus": [Function],
22
+ },
23
+ ]
24
+ `;
@@ -0,0 +1,148 @@
1
+ // noinspection TypeScriptUnresolvedVariable, ES6UnusedImports, JSUnusedLocalSymbols, TypeScriptCheckImport
2
+ import { DeepRequired } from "ts-essentials"
3
+ import { Maybe, IResponseListener, Endpoint } from "."
4
+
5
+ // Scalars
6
+ export type IDate = string | Date
7
+ export declare type ISODate = IDate
8
+
9
+ // Enums
10
+
11
+ export declare enum BookType {
12
+ dolor = "DOLOR",
13
+ ipsum = "IPSUM",
14
+ sit = "SIT",
15
+ }
16
+
17
+ type AllEnums = BookType
18
+
19
+ // Args
20
+ export interface BooksWithoutParamsArgs {}
21
+ export interface BooksWithOptionalParamsArgs {
22
+ params?: BookSearchParamsAllOptional
23
+ }
24
+ export interface BooksWithRequiredParamsArgs {
25
+ params: BookSearchParamsSomeRequired
26
+ }
27
+ export interface FailingQueryArgs {
28
+ id: string
29
+ }
30
+
31
+ // Input/Output Types
32
+
33
+ /**
34
+ * @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
35
+ */
36
+
37
+ export interface Book {
38
+ title?: string
39
+ author?: string
40
+ type?: BookType
41
+ dateCreated?: ISODate
42
+ }
43
+
44
+ /**
45
+ * @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
46
+ */
47
+
48
+ export interface BookSearchParamsAllOptional {
49
+ title?: string
50
+ author?: string
51
+ createdAfter?: ISODate
52
+ }
53
+
54
+ /**
55
+ * @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
56
+ */
57
+
58
+ export interface BookSearchParamsSomeRequired {
59
+ title: string
60
+ author?: string
61
+ }
62
+
63
+ /**
64
+ * @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
65
+ */
66
+
67
+ export interface Query {
68
+ booksWithoutParams?: Book[]
69
+ booksWithOptionalParams?: Book[]
70
+ booksWithRequiredParams?: Book[]
71
+ failingQuery?: string
72
+ }
73
+
74
+ // Selection Types
75
+
76
+ export interface BookSelection {
77
+ title?: boolean
78
+ author?: boolean
79
+ type?: boolean
80
+ dateCreated?: boolean
81
+ }
82
+
83
+ export interface BookSearchParamsAllOptionalSelection {
84
+ title?: boolean
85
+ author?: boolean
86
+ createdAfter?: boolean
87
+ }
88
+
89
+ export interface BookSearchParamsSomeRequiredSelection {
90
+ title?: boolean
91
+ author?: boolean
92
+ }
93
+
94
+ export declare const myApiClient: {
95
+ addResponseListener: (listener: IResponseListener) => void
96
+ setHeader: (key: string, value: string) => void
97
+ setHeaders: (newHeaders: { [k: string]: string }) => void
98
+ setUrl: (url: string) => void
99
+ setRetryConfig: (options: {
100
+ max: number
101
+ waitBeforeRetry?: number
102
+ before?: IResponseListener
103
+ }) => void
104
+ queries: {
105
+ booksWithoutParams: Endpoint<
106
+ {
107
+ __headers?: { [key: string]: string }
108
+ __retry?: boolean
109
+ __alias?: string
110
+ } & BookSelection,
111
+ DeepRequired<Book[]>,
112
+ AllEnums
113
+ >
114
+ booksWithOptionalParams: Endpoint<
115
+ {
116
+ __headers?: { [key: string]: string }
117
+ __retry?: boolean
118
+ __alias?: string
119
+ __args?: BooksWithOptionalParamsArgs
120
+ } & BookSelection,
121
+ DeepRequired<Book[]>,
122
+ AllEnums
123
+ >
124
+ booksWithRequiredParams: Endpoint<
125
+ {
126
+ __headers?: { [key: string]: string }
127
+ __retry?: boolean
128
+ __alias?: string
129
+ __args: BooksWithRequiredParamsArgs
130
+ } & BookSelection,
131
+ DeepRequired<Book[]>,
132
+ AllEnums
133
+ >
134
+ failingQuery: Endpoint<
135
+ {
136
+ __headers?: { [key: string]: string }
137
+ __retry?: boolean
138
+ __alias?: string
139
+ __args: FailingQueryArgs
140
+ },
141
+ string,
142
+ AllEnums
143
+ >
144
+ }
145
+ mutations: {}
146
+ }
147
+
148
+ export default myApiClient
@@ -0,0 +1,118 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var stdin_exports = {};
29
+ __export(stdin_exports, {
30
+ BookType: () => BookType,
31
+ default: () => stdin_default,
32
+ myApiClient: () => myApiClient
33
+ });
34
+ module.exports = __toCommonJS(stdin_exports);
35
+ var import_endpoint = require("./endpoint");
36
+ var import_standalone = require("prettier/standalone");
37
+ var import_parser_graphql = __toESM(require("prettier/parser-graphql"));
38
+ const formatGraphQL = (query) => (0, import_standalone.format)(query, { parser: "graphql", plugins: [import_parser_graphql.default] });
39
+ const BookType = {
40
+ dolor: "DOLOR",
41
+ ipsum: "IPSUM",
42
+ sit: "SIT"
43
+ };
44
+ const typesTree = {
45
+ Query: {
46
+ get booksWithOptionalParams() {
47
+ return {
48
+ __args: {
49
+ params: "BookSearchParamsAllOptional!"
50
+ }
51
+ };
52
+ },
53
+ get booksWithRequiredParams() {
54
+ return {
55
+ __args: {
56
+ params: "BookSearchParamsSomeRequired!"
57
+ }
58
+ };
59
+ },
60
+ get failingQuery() {
61
+ return {
62
+ __args: {
63
+ id: "String!"
64
+ }
65
+ };
66
+ },
67
+ booksWithoutParams: {}
68
+ }
69
+ };
70
+ let verbose = false;
71
+ let headers = {};
72
+ let url = "http://localhost:4123/graphql";
73
+ let retryConfig = {
74
+ max: 0,
75
+ before: void 0,
76
+ waitBeforeRetry: 0
77
+ };
78
+ let responseListeners = [];
79
+ let errorsParser = void 0;
80
+ let apiEndpoint = (0, import_endpoint.getApiEndpointCreator)({
81
+ getClient: () => ({ url, headers, retryConfig }),
82
+ responseListeners,
83
+ maxAge: 3e4,
84
+ verbose,
85
+ typesTree,
86
+ formatGraphQL,
87
+ errorsParser
88
+ });
89
+ const myApiClient = {
90
+ addResponseListener: (listener) => responseListeners.push(
91
+ listener
92
+ ),
93
+ setHeader: (key, value) => {
94
+ headers[key] = value;
95
+ },
96
+ setHeaders: (newHeaders) => {
97
+ headers = newHeaders;
98
+ },
99
+ setRetryConfig: (options) => {
100
+ if (!Number.isInteger(options.max) || options.max < 0) {
101
+ throw new Error("retryOptions.max should be a non-negative integer");
102
+ }
103
+ retryConfig = {
104
+ max: options.max,
105
+ waitBeforeRetry: options.waitBeforeRetry,
106
+ before: options.before
107
+ };
108
+ },
109
+ setUrl: (_url) => url = _url,
110
+ queries: {
111
+ booksWithoutParams: apiEndpoint("query", "booksWithoutParams"),
112
+ booksWithOptionalParams: apiEndpoint("query", "booksWithOptionalParams"),
113
+ booksWithRequiredParams: apiEndpoint("query", "booksWithRequiredParams"),
114
+ failingQuery: apiEndpoint("query", "failingQuery")
115
+ },
116
+ mutations: {}
117
+ };
118
+ var stdin_default = myApiClient;
@@ -0,0 +1,117 @@
1
+ import memoize from 'moize'
2
+ import { graphqlRequest } from './graphqlRequest'
3
+ import { jsonToGraphQLQuery } from './jsonToGraphQLQuery'
4
+ import { logRequest } from './logging'
5
+ import {ClientConfig, Endpoint, GraphQLClientError, IResponseListener, Projection, ResponseListenerInfo} from './types'
6
+
7
+ const executeListeners = (listeners: IResponseListener[], data: ResponseListenerInfo) =>
8
+ setTimeout(() =>
9
+ listeners.forEach(runResponseListener =>
10
+ runResponseListener(data)
11
+ )
12
+ )
13
+
14
+ export const getApiEndpointCreator =
15
+ (apiConfig: {
16
+ getClient: () => ClientConfig
17
+ responseListeners: IResponseListener[]
18
+ typesTree: any
19
+ maxAge: number
20
+ verbose: boolean
21
+ formatGraphQL: any
22
+ errorsParser?: (errors: any[]) => any
23
+ }) =>
24
+ <I = any, O = any, E = any>(kind: 'mutation' | 'query', queryName: string): Endpoint<I, O, E> => {
25
+ const rawEndpoint: any = async <S extends I>(
26
+ failureMode: 'loud' | 'silent',
27
+ jsonQuery?: S
28
+ ): Promise<{
29
+ data: Projection<S, O>
30
+ errors: any[]
31
+ warnings: any[]
32
+ headers: any
33
+ status: any
34
+ }> => {
35
+ const alias = (jsonQuery as any)?.__alias ?? queryName
36
+ const shouldRetry = (jsonQuery as any)?.__retry ?? true
37
+ const requestHeaders = (jsonQuery as any)?.__headers ?? {}
38
+ const { query, variables } = jsonToGraphQLQuery({ kind, queryName, jsonQuery, typesTree: apiConfig.typesTree })
39
+ const start = +new Date()
40
+
41
+ const logOptions = {
42
+ kind,
43
+ queryName: alias,
44
+ formatGraphQL: apiConfig.formatGraphQL,
45
+ requestHeaders,
46
+ query,
47
+ variables,
48
+ }
49
+
50
+ const responseListenerData = {
51
+ queryName: alias,
52
+ query: apiConfig.formatGraphQL(query),
53
+ variables,
54
+ }
55
+
56
+ try {
57
+ const { data, errors, warnings, headers, status } = await graphqlRequest({
58
+ shouldRetry,
59
+ failureMode,
60
+ queryName: alias,
61
+ client: apiConfig.getClient(),
62
+ requestHeaders,
63
+ query,
64
+ variables,
65
+ errorsParser: apiConfig.errorsParser
66
+ })
67
+
68
+ const response = { data, warnings, headers, status, errors }
69
+
70
+ if (apiConfig.verbose && globalThis.document) {
71
+ logRequest({
72
+ ...logOptions,
73
+ response,
74
+ duration: +new Date() - start,
75
+ })
76
+ }
77
+
78
+ executeListeners(apiConfig.responseListeners,{
79
+ ...responseListenerData,
80
+ response,
81
+ })
82
+
83
+ return { data: data?.[alias], errors, warnings, headers, status }
84
+ } catch (error) {
85
+ if (apiConfig.verbose && globalThis.document) {
86
+ logRequest({
87
+ ...logOptions,
88
+ error: error as Error,
89
+ duration: +new Date() - start,
90
+ })
91
+ }
92
+
93
+ executeListeners(apiConfig.responseListeners, {
94
+ ...responseListenerData,
95
+ response: (error as GraphQLClientError).response,
96
+ })
97
+
98
+ throw error
99
+ }
100
+ }
101
+
102
+ const endpoint: any = async <S extends I>(jsonQuery?: S): Promise<Projection<S, O>> => {
103
+ const { data } = await rawEndpoint('loud', jsonQuery)
104
+ return data
105
+ }
106
+
107
+ const memoizeeOptions = {
108
+ maxAge: apiConfig.maxAge,
109
+ isSerialized: true,
110
+ }
111
+
112
+ endpoint.raw = rawEndpoint.bind(null, 'silent')
113
+ endpoint.memo = memoize(endpoint, memoizeeOptions)
114
+ endpoint.memoRaw = memoize(endpoint.raw, memoizeeOptions)
115
+
116
+ return endpoint
117
+ }
@@ -0,0 +1,127 @@
1
+ import { ApolloServer } from 'apollo-server'
2
+ import * as path from 'path'
3
+ import { generateTypescriptClient } from './generateTypescriptClient'
4
+ import { startServer } from './testServer'
5
+ import { GraphQLClientError, ResponseListenerInfo } from './types'
6
+
7
+ let testServer: { server: ApolloServer; url: string }
8
+ let client: any
9
+
10
+ describe('Generated Client', () => {
11
+ beforeAll(async () => {
12
+ testServer = await startServer()
13
+
14
+ const clientName = 'myApiClient'
15
+
16
+ const { js } = await generateTypescriptClient({
17
+ clientName,
18
+ endpoint: `${testServer.url}graphql`,
19
+ // For the sake of checking the generated code, we'll
20
+ // specify an output path
21
+ output: path.resolve(__dirname, './__testClient.ts'),
22
+ formatGraphQL: true,
23
+ skipCache: true,
24
+ })
25
+
26
+ client = eval(`${js};${clientName}`)
27
+ })
28
+
29
+ afterAll(async () => await testServer.server.stop())
30
+
31
+ it('should be able to pass custom headers to a query without args', async () => {
32
+ const books = await client.queries.booksWithoutParams({
33
+ __headers: { 'X-Custom-Header': 'Foo' },
34
+ title: true,
35
+ author: true,
36
+ })
37
+
38
+ expect(books).toHaveLength(2)
39
+ expect(books[0]).toHaveProperty('title')
40
+ expect(books[0]).toHaveProperty('author')
41
+ })
42
+
43
+ it('should be able to make queries with optional args, not passing args obj', async () => {
44
+ // noinspection TypeScriptValidateJSTypes
45
+ const books = await client.queries.booksWithOptionalParams({
46
+ title: true,
47
+ author: true,
48
+ })
49
+
50
+ expect(books).toHaveLength(2)
51
+ expect(books[0]).toHaveProperty('title')
52
+ expect(books[0]).toHaveProperty('author')
53
+ })
54
+
55
+ it('should be able to make queries with optional args, not passing args obj', async () => {
56
+ // noinspection TypeScriptValidateJSTypes
57
+ const books = await client.queries.booksWithOptionalParams({
58
+ __alias: 'helloWorld',
59
+ title: true,
60
+ author: true,
61
+ })
62
+
63
+ expect(books).toHaveLength(2)
64
+ expect(books[0]).toHaveProperty('title')
65
+ expect(books[0]).toHaveProperty('author')
66
+ })
67
+
68
+ it('fail with broken queries', async () => {
69
+ const result = await client.queries
70
+ .failingQuery({
71
+ __args: {
72
+ id: 'hello',
73
+ },
74
+ })
75
+ .then(
76
+ () => 'success',
77
+ (err: any) => err
78
+ )
79
+
80
+ expect(result).toBeInstanceOf(GraphQLClientError)
81
+ expect(result.message).toBe('Failed lorem ipsum dolor')
82
+ })
83
+
84
+ it('does not fail with broken queries when using raw requests', async () => {
85
+ const result = await client.queries.failingQuery.raw({
86
+ __args: {
87
+ id: 'hello',
88
+ },
89
+ })
90
+
91
+ expect(result.status).toBe(200)
92
+ expect(result.errors).toHaveLength(1)
93
+ expect(result.errors[0].message).toBe('Failed lorem ipsum dolor')
94
+ })
95
+
96
+ it('failing operations throw errors', async () => {
97
+ let failed = false
98
+
99
+ try {
100
+ await client.queries.failingQuery({
101
+ __args: {
102
+ id: 'hello',
103
+ },
104
+ })
105
+ } catch (err) {
106
+ failed = true
107
+ }
108
+
109
+ expect(failed).toBe(true)
110
+ })
111
+
112
+ it('failing operations throw errors', async () => {
113
+ let responseData: ResponseListenerInfo | undefined
114
+ client.addResponseListener((data: any) => (responseData = data))
115
+
116
+ try {
117
+ await client.queries.failingQuery({
118
+ __args: {
119
+ id: 'hello',
120
+ },
121
+ })
122
+ } catch {}
123
+
124
+ expect(responseData?.queryName).toBe('failingQuery')
125
+ expect(responseData?.response.errors.length).toBeGreaterThan(0)
126
+ })
127
+ })