npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

mercurius-integration-testing

v9.0.0

Published

[![npm version](https://badge.fury.io/js/mercurius-integration-testing.svg)](https://badge.fury.io/js/mercurius-integration-testing) [![codecov](https://codecov.io/gh/PabloSzx/mercurius-integration-testing/branch/master/graph/badge.svg)](https://codecov.i

Downloads

18,162

Readme

mercurius-integration-testing

npm version codecov

pnpm add mercurius-integration-testing
# or
yarn add mercurius-integration-testing
# or
npm install mercurius-integration-testing

Features

Table of Contents

Usage

// app.ts | app.js
import Fastify from 'fastify'
import Mercurius from 'mercurius'
import schema from './schema'
import { buildContext } from './buildContext'

export const app = Fastify()

app.register(Mercurius, {
  schema,
  resolvers: {},
  context: buildContext,
  allowBatchedQueries: true,
})
// integration.test.js | integration.test.ts

import { createMercuriusTestClient } from 'mercurius-integration-testing'
import { app } from '../app'

// ...

const testClient = createMercuriusTestClient(app)

expect(testClient.query('query { helloWorld }')).resolves.toEqual({
  data: {
    helloWorld: 'helloWorld',
  },
})

API

createMercuriusTestClient

Create a testing client instance, you should give it the fastify instance in which Mercurius was already registered, and optionally, some options

const client = createMercuriusTestClient(app, {
  /**
   * Optional, specify headers to be added to every request in the client
   */
  headers: {
    authorization: 'hello-world',
  },
  /**
   * Optional, by default it points to /graphql
   */
  url: '/graphql',
  /**
   * Optional, specify cookies to be added to every request in the client
   */
  cookies: {
    authorization: 'hello-world',
  },
})

query, mutate

.query and .mutate are basically the same function, but for readability, both exists

// You can give it a simple string
const queryResponse = await client.query(`
query {
  helloWorld
}
`)

// Data returned from the API
queryResponse.data

// Possible array of errors from the API
queryResponse.errors

// You can also call `mutate`
// to improve readability for mutations
const mutationResponse = await client.mutate(`
mutation {
  helloWorld
}
`)
DocumentNode support
// You can also give them `DocumentNode`s
// from `graphql-tag` or equivalents
await client.query(gql`
  query {
    helloWorld
  }
`)
Variables
// You can give variables in the second parameter options
await client.query(
  `
  query($foo: String!) {
    hello(foo: $foo)
  }
`,
  {
    variables: {
      foo: 'bar',
    },
  }
)
Other options
await client.query(
  `
  query example {
    helloExample
  }
`,
  {
    // You can specify operation name if the queries
    // are named
    operationName: 'helloExample',
    // Query specific headers
    // These are going to be "merged" with the client set headers
    headers: {
      hello: 'world',
    },

    // Query specific cookies
    // These are going to be "merged" with the client set headers
    cookies: {
      foo: 'bar',
    },
  }
)

setHeaders

You can change the default client headers whenever

client.setHeaders({
  authorization: 'other-header',
})

setCookies

You can change the default client cookies whenever

client.setCookies({
  authorization: 'other-cookie',
})

batchQueries

If allowBatchedQueries is set in the Mercurius registration, you can call some queries together

const batchedResponse = await client.batchQueries(
  [
    {
      query: `
  query {
    helloWorld
  }
  `,
    },
    {
      query: `
  query($name: String!) {
    user(name: $name) {
      email
    }
  }
  `,
      variables: {
        name: 'bob',
      },
      // operationName: "you-can-specify-it-here-if-needed"
    },
  ],
  // Optional
  {
    // Optional request specific cookies
    cookies: {
      foo: 'bar',
    },
    // Optional request specific headers
    headers: {
      foo: 'bar',
    },
  }
)

batchedResponse ===
  [
    { data: { helloWorld: 'foo' } },
    { data: { user: { email: '[email protected]' } } },
  ]

subscribe

If you are not already calling .listen(PORT) somewhere, it will automatically call it, assigning a random available port, this means you will have to manually call .close() somewhere

.subscribe returns a promise that resolves when the subscription connection is made

headers & cookies are applied the same as in .query and .mutate

const subscription = await client.subscribe({
  query: `
  subscription {
    notificationAdded {
      id
      message
    }
  }
  `,
  onData(response) {
    // response.errors => array of graphql errors or undefined
    response ==
      { data: { notificationAdded: { id: 1, message: 'hello world' } } }
  },
  // Optional
  variables: { foo: 'bar' },
  // Optional
  operationName: 'name_if_is_named_query',
  // Optional, initialization payload, usually for authorization
  initPayload: { authorization: '<token>' },
  // Optional, subscription specific cookies
  cookies: {
    authorization: '<token>',
  },
  // Optional, subscription specific headers
  headers: {
    authorization: '<token>',
  },
})

// You can manually call the unsubscribe

subscription.unsubscribe()

// You will need to manually close the fastify instance somewhere

app.close()

getFederatedEntity

In a federated service it's useful to test if a service is extending the entity correctly.

This function is a wrapper around _entities query.

An entity can be federated on a single field:

import { mercuriusFederationPlugin } from '@mercuriusjs/federation'

const schema = `
    type Post @key(fields: "id") {
      id: ID! @external
      description: String!
    }
  
    extend type User @key(fields: "id") {
      id: ID! @external
      posts: [Post!]!
    }
  `

const app = fastify()
app.register(mercuriusFederationPlugin, {
  schema,
  resolvers: {
    User: {
      posts: () => [{ id: 'post-id', description: 'Post description' }],
    },
  },
})

const client = createMercuriusTestClient(app)

const entity = await client.getFederatedEntity({
  typename: 'User',
  keys: { id: 'user1' },
  typeQuery: `
        id
        posts {
          id
          description
        }`,
})

entity ===
  {
    __typename: 'User',
    id: 'user1',
    posts: [
      {
        id: 'post-id',
        description: 'Post description',
      },
    ],
  }

or on multiple fields:

const schema = `
      type ProductCategory {
        id: ID!
        name: String!
      }
    
      extend type Product @key(fields: "sku") @key(fields: "upc") {
        upc: String! @external
        sku: Int! @external
        category: ProductCategory
      }
    `

const app = fastify()
app.register(mercuriusFederationPlugin, {
  schema,
  resolvers: {
    Product: {
      category: () => ({ id: 'product-category', name: 'Stub category' }),
    },
  },
})

const client = createMercuriusTestClient(app)

const entity = await client.getFederatedEntity({
  typename: 'Product',
  keys: { sku: 1, upc: 'upc' },
  typeQuery: `
          upc
          sku
          category {
            id
            name
          }`,
})

entity ===
  {
    __typename: 'Product',
    upc: 'upc',
    sku: 1,
    category: {
      id: 'product-category',
      name: 'Stub category',
    },
  }

TypeScript

const dataResponse = await client.query<{
  helloWorld: string
}>(`
query {
  helloWorld
}
`)

// string
dataResponse.data.helloWorld

const variablesResponse = await client.query<
  {
    user: {
      email: string
    }
  },
  {
    name: string
  }
>(
  `
  query($name: String!) {
    user(name: $name) {
      email
    }
  }
`,
  {
    variables: {
      name: 'bob',
    },
  }
)

// string
variablesResponse.data.user.email

await client.subscribe<
  {
    helloWorld: string
  },
  {
    foo: string
  }
>({
  query: `
  subscription($foo: String!) {
    helloWorld(foo: $foo)
  }
  `,
  variables: {
    // Error, Type 'number' is not assignable to type 'string'.
    foo: 123,
  },
  onData(response) {
    // string
    response.data.helloWorld
  },
})

License

MIT