diff --git a/src/__fixtures__/hooksTestHelper.ts b/src/__fixtures__/hooksTestHelper.ts index 5dda247..8f8b277 100644 --- a/src/__fixtures__/hooksTestHelper.ts +++ b/src/__fixtures__/hooksTestHelper.ts @@ -11,9 +11,10 @@ governing permissions and limitations under the License. */ import { buildHTTPExecutor, SyncFetchFn } from '@graphql-tools/executor-http'; -import { createSchema, YogaInitialContext, YogaServer } from 'graphql-yoga'; +import { createSchema, Plugin, YogaInitialContext, YogaServer } from 'graphql-yoga'; import { parse } from 'graphql'; import { HookFunctionPayload, HookResponse, HookStatus, UserContext } from '../types'; +import { TypedExecutionArgs } from '@envelop/core'; const mockSuccessResponse: HookResponse = { status: HookStatus.SUCCESS, @@ -30,7 +31,15 @@ const convertMockResponseToContext = (mockResponse: HookResponse) => body: mockResponse, }) as unknown as HookFunctionPayload; -const testFetch = (yogaServer: YogaServer, query: string) => { +const mockSecrets = { + mockSecret: 'mockSecretValue', +}; + +const testFetch = ( + yogaServer: YogaServer, + query: string, + operationName?: string, +) => { if (!('fetch' in yogaServer)) { throw new Error('Unable to test YogaServer via fetch executor'); } @@ -39,9 +48,11 @@ const testFetch = (yogaServer: YogaServer, quer fetch: yogaServer.fetch as SyncFetchFn, }); + const useOperationName = operationName || 'TestQuery'; return Promise.resolve( executor({ document: parse(query), + operationName: useOperationName, }), ); }; @@ -60,14 +71,28 @@ const mockSchema = createSchema({ }); const mockQuery = /* GraphQL */ ` - query { + query TestQuery { hello } `; +async function extractArgsPlugin( + ref: + | TypedExecutionArgs + | TypedExecutionArgs, +): Promise> { + return { + async onExecute({ args }) { + Object.assign(ref, args); + }, + }; +} + export { convertMockResponseToContext, + extractArgsPlugin, mockErrorResponse, + mockSecrets, mockSchema, mockSuccessResponse, mockQuery, diff --git a/src/__tests__/index.test.ts b/src/__tests__/index.test.ts index cc4307a..26fb0e1 100644 --- a/src/__tests__/index.test.ts +++ b/src/__tests__/index.test.ts @@ -10,11 +10,16 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ +import { TypedExecutionArgs } from '@envelop/core'; import { createYoga, YogaServer, YogaInitialContext } from 'graphql-yoga'; +import { Readable } from 'node:stream'; import { beforeEach } from 'vitest'; import { + extractArgsPlugin, + mockErrorResponse, mockQuery, mockSchema, + mockSecrets, mockSuccessResponse, testFetch, } from '../__fixtures__/hooksTestHelper'; @@ -27,6 +32,9 @@ let mockModule: Module; describe('hooksPlugin', () => { let yogaServer: YogaServer; + const argsReference = {} as + | TypedExecutionArgs + | TypedExecutionArgs; beforeEach(async () => { mockHook = vi.fn(); mockModule = { mockHook }; @@ -41,7 +49,14 @@ describe('hooksPlugin', () => { fn: 'mockHook', }, }), + await extractArgsPlugin(argsReference), ], + context: initialContext => { + return { + ...initialContext, + secrets: mockSecrets, + }; + }, schema: mockSchema, }); vi.resetAllMocks(); @@ -62,10 +77,29 @@ describe('hooksPlugin', () => { }); test('should skip introspection queries', async () => { expect(mockHook).toHaveBeenCalledTimes(0); - await testFetch(yogaServer, 'query IntrospectionQuery { __schema { types { name } } }'); + await testFetch( + yogaServer, + 'query IntrospectionQuery { __schema { types { name } } }', + 'IntrospectionQuery', + ); expect(mockHook).toHaveBeenCalledTimes(0); }); - test('should update headers in context', async () => { + test('should have access to expected context/payload', async () => { + mockHook.mockImplementationOnce(() => mockSuccessResponse); + expect(mockHook).toHaveBeenCalledTimes(0); + await testFetch(yogaServer, mockQuery); + expect(mockHook).toHaveBeenCalledTimes(1); + expect(argsReference.contextValue.params).toBeDefined(); + expect(argsReference.contextValue.request).toBeDefined(); + expect(argsReference.contextValue.request.body).toBeInstanceOf(Readable); + const headers = + 'headers' in argsReference.contextValue ? argsReference.contextValue.headers : undefined; + expect(headers).toEqual(undefined); + const secrets = + 'secrets' in argsReference.contextValue ? argsReference.contextValue.secrets : undefined; + expect(secrets).toEqual(mockSecrets); + }); + test('should be able to update headers in context', async () => { mockHook.mockImplementation(() => { return { ...mockSuccessResponse, @@ -79,19 +113,30 @@ describe('hooksPlugin', () => { expect(mockHook).toHaveBeenCalledTimes(0); await testFetch(yogaServer, mockQuery); expect(mockHook).toHaveBeenCalledTimes(1); + expect(argsReference.contextValue.params.query).toEqual(`query TestQuery{hello}`); + expect(argsReference.operationName).toEqual('TestQuery'); + const headers = + 'headers' in argsReference.contextValue ? argsReference.contextValue.headers : {}; + expect(headers).toEqual( + expect.objectContaining({ + 'x-mock-header': 'mock-value', + }), + ); }); test('should invoke beforeAll hook', async () => { expect(mockHook).toHaveBeenCalledTimes(0); await testFetch(yogaServer, mockQuery); expect(mockHook).toHaveBeenCalledTimes(1); }); - // test('should return GraphQL error when error', async () => { - // mockHook.mockImplementationOnce(() => mockErrorResponse); - // expect(mockHook).toHaveBeenCalledTimes(0); - // const response = await testFetch(yogaServer, mockQuery); - // const data = await response.json(); - // expect(mockHook).toHaveBeenCalledTimes(1); - // expect(data.errors.length).toBe(1); - // expect(data.errors[0].message).toEqual(mockErrorResponse.message); - // }); + test('should return GraphQL error when error', async () => { + mockHook.mockImplementationOnce(() => mockErrorResponse); + expect(mockHook).toHaveBeenCalledTimes(0); + const response = await testFetch(yogaServer, mockQuery); + expect(mockHook).toHaveBeenCalledTimes(1); + expect(response.data).toBeNull(); + expect(response.errors).not.toBeUndefined(); + const errors = response.errors!; + expect(errors.length).toBe(1); + expect(errors[0].message).toEqual(mockErrorResponse.message); + }); }); diff --git a/src/index.ts b/src/index.ts index 09072ca..7b10988 100644 --- a/src/index.ts +++ b/src/index.ts @@ -39,7 +39,6 @@ export default async function hooksPlugin(config: PluginConfig): Promise