1.2.2 β€’ Published 2 months ago

playwright-graphql v1.2.2

Weekly downloads
-
License
MIT
Repository
github
Last release
2 months ago

Playwright-graphql

This library provides Playwright integration with GraphQL and TypeScript for efficient API testing. It enables you to generate an auto-generated GraphQL API client with autocomplete functionality.

DEMO

🌟 Features

  • πŸš€ Autogenerated GraphQL API client with TypeScript autocomplete
  • πŸ“Š Comprehensive schema and operation generation
  • πŸ” Flexible request handling and response management
  • πŸ“ˆ Optional GraphQL coverage reporting

To build the GraphQL client, this library leverages several GraphQL libraries, such as:

The build-in CLI simplifies code generation process to one simple command.

playwright-graphql --schema schema.gql

Project setup:

  1. Installation.
  2. Generate type safe client.
  3. Add GraphQL client fixture.
  4. Write GraphQL tests with joy!

Template project: https://github.com/DanteUkraine/playwright-graphql-example

Installation

To begin, install the playwright-graphql package. This library integrates GraphQL testing with Playwright and TypeScript, offering autocomplete and type safety for your API tests.

  • npm install playwright-graphql

or for dev dependency

  • npm install -D playwright-graphql

Generate type safe client

playwright-graphql --schema path-to-schema.gql

Will generate you next:

πŸ“ Project Root
β”œβ”€β”€ πŸ“„ path-to-schema.gql (existing schema file)
β”œβ”€β”€ πŸ“„ codegen.ts (generated config file)
└── πŸ“ gql (default directory for generated files)
    β”œβ”€β”€ πŸ“ autogenerated-operations (contains all possible GraphQL operations)
    β”‚   β”œβ”€β”€ πŸ“„ mutations.gql
    β”‚   └── πŸ“„ queries.gql
    └── πŸ“„ graphql.ts (generated TypeScript types and client)

When you run the command with an existing schema file, the CLI will:

  1. Generate GraphQL operations based on your schema
  2. Create a codegen configuration file
  3. Generate TypeScript types for type-safe GraphQL operations
  4. Add a client utility function for use with Playwright tests

The generated graphql.ts file will include a getClient(apiContext, options?, callback?) function and type GqlAPI that you can use in your Playwright fixture to return type-safe GraphQL client in tests.

In case you can not generate schema from GraphQL server directly:

playwright-graphql --url http://localhost:4000/api/graphql --schema schema.gql

Will generate you next:

πŸ“ Project Root
β”œβ”€β”€ πŸ“„ schema.gql (generated schema file)
β”œβ”€β”€ πŸ“„ codegen.ts (generated config file)
└── πŸ“ gql (default directory for generated files)
    β”œβ”€β”€ πŸ“ autogenerated-operations (contains all possible GraphQL operations)
    β”‚   β”œβ”€β”€ πŸ“„ mutations.gql
    β”‚   └── πŸ“„ queries.gql
    └── πŸ“„ graphql.ts (generated TypeScript types and client)

When you run the command with a GraphQL endpoint URL, the CLI will:

  1. Fetch the GraphQL schema from the specified URL
  2. Save the schema to the specified file (schema.gql)
  3. Generate GraphQL operations based on the fetched schema
  4. Create a codegen configuration file
  5. Generate TypeScript types for type-safe GraphQL operations
  6. Add a client utility function for use with Playwright tests

This command is useful when you want to generate or update your schema file directly from a GraphQL endpoint. It combines the schema fetching step with the type-safe client generation, streamlining the setup process for your Playwright GraphQL tests.

The generated files and their purposes remain the same as in the previous command, but now you have the added benefit of automatically fetching and updating your schema file from the live GraphQL endpoint.

Add path to your tsconfig

To simplify your imports and improve project readability, configure your tsconfig.json by adding custom path aliases. This makes it easier to import your generated GraphQL client across your project:

Add "@gql": ["gql/graphql"] for easy import.

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "strict": true,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "noFallthroughCasesInSwitch": true,
    "allowSyntheticDefaultImports": true,
    "baseUrl": "./",
    "paths": {
      "@fixtures/*": ["fixtures/*"],
      "@gql": ["gql/graphql"]
    }
  }
}

This setup allows you to import your client like this:

import { getClient, GqlAPI } from '@gql';

Note that the @fixtures/* path alias allows you to import any file from the fixtures directory as a module:

import { test, expect } from '@fixtures/gql';

Instead of using long relative paths.

Create gql fixture

The final step creates a fixture for integrating the autogenerated GraphQL client with Playwright tests. The fixture returns Playwright GraphQl type safe API client into tests. Create a file (minimalistic example, fixtures/gql.ts) with the following content:

fixtures/gql.ts

import { test as baseTest, expect, request, APIRequestContext } from '@playwright/test';
import { getClient, GqlAPI } from '@gql';

export { expect };

type WorkerFixtures = {
    apiContext: APIRequestContext;
    gql: GqlAPI;
};

export const test = baseTest.extend<{}, WorkerFixtures>({
    apiContext: [
      async ({}, use) => {
        const apiContext = await request.newContext({
          baseURL: 'http://localhost:4000'
        });
        await use(apiContext);
      }, { scope: 'worker' } 
    ],
    gql: [
        async ({ apiContext }, use) => {
            await use(getClient(apiContext));
        }, { auto: false, scope: 'worker' }
    ]
});

This fixture ensures that your tests have a consistent and type-safe GraphQL client available, and it leverages Playwright’s API request context for efficient testing.

Full configurability example:

import { test as baseTest, expect, request, APIRequestContext } from '@playwright/test';
import { getClient, GqlAPI, RequesterOptions, RequestHandler } from '@gql';

export { expect };

const options: RequesterOptions = {
  gqlEndpoint: 'api/gql', 
  rawResponse: true
};

// This optional callback allows user to add custom logic to gql api call.
const requestHandlerCallback: RequestHandler = async (request: () => Promise<APIResponse>) => {
  console.log('Before api call');
  const res = await request();
  console.log(`After api call: ${res.status()}`);
  return res;
};

type WorkerFixtures = {
    apiContext: APIRequestContext;
    gql: GqlAPI;
};

export const test = baseTest.extend<{}, WorkerFixtures>({
    apiContext: [
      async ({}, use) => {
        const apiContext = await request.newContext({
          baseURL: 'http://localhost:4000'
        });
        await use(apiContext);
      }, { scope: 'worker' } 
    ],
    gql: [
        async ({ apiContext }, use) => {
            await use(getClient(apiContext, options, requestHandlerCallback));
        }, { auto: false, scope: 'worker' }
    ]
});

This full example shows how to customize GraphQL endpoint, type of response, and add custom logic to GraphQL API calls.

Now, you can write your tests using the fixture.

You are ready to jump into writing tests!

tests/example.test:

import { test, expect } from '@fixtures/gql';

test('playwright-graphql test', async ({ gql }) => {
    const res = await gql.getCityByName({
        name: 'Lviv'
    });

    expect(res.getCityByName).not.toBeNull();
})

Code generation with build in CLI

Designed for common workflow, the playwright-graphql CLI tool automates the process of generating GraphQL schemas, operations, and TypeScript types for your Playwright tests.

Examples:

Basic schema generation with default settings:

  • playwright-graphql --url http://localhost:4000/api/graphql

Schema generation with authentication:

  • playwright-graphql --url http://localhost:4000/api/graphql --header "Authorization: Bearer token"

Syntax for complex headers:

  • playwright-graphql --url http://localhost:4000/api/graphql -h "Cookies={'Authorization': 'Bearer token'}"

Keep in mind that you can use multiple headers in single command.

Custom paths for generated files:

  • playwright-graphql --url http://localhost:4000/api/graphql --gqlDir src/graphql --gqlFile operations.ts

Using an existing schema file:

  • playwright-graphql --schema existing-schema.gql

Enabling coverage logging:

  • playwright-graphql --url http://localhost:4000/api/graphql --coverage

This command fetches the GraphQL schema from your endpoint and generates the necessary files for type-safe GraphQL operations in your Playwright tests.

CLI Options

The CLI tool accepts several options to customize its behavior. Below is a summary of the available command-line parameters:

OptionAliasDescriptionTypeDefault
--url-uFull GraphQL endpoint URL used for schema retrieval. In case this option is not passed, the script will skip schema generation and will look for an existing schema.stringoptional
--schema-sPath to save the generated GraphQL schema file. If the URL option is not provided, the script expects that the schema already exists.stringschema.gql
--header-hOptional authentication header(s) for schema fetching. Can be passed multiple times.arrayoptional
--gqlDir-dPath to save the auto-generated GraphQL files.stringgql
--gqlFile-fPath to save the auto-generated GraphQL queries, mutations, and TypeScript types.stringgraphql.ts
--rawMakes Graphql api return raw responses.booleanfalse
--codegen-cPath to save the codegen config for TypeScript types.stringcodegen.ts
--coverageFlag to add coverage logger to auto-generated client.booleanfalse
--versionPrint version.
--helpPrint all CLI options.

Return raw response body instead of schema defined type.

You can configure the library to return the raw GraphQL response body instead of the schema-defined types. This is useful when you need full control over the response payload.

Steps to Enable Raw Response:

  1. Add rawRequest: true under the codegen.ts file. Note that when rawRequest is set to true, you must also enable rawResponse in your client setup: getClient(apiContext, { rawResponse: true }).

codegen.ts file:

import type { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
  overwrite: true,
  schema: './schema.gql',
  documents: [
    'gql/autogenerated-operations/**/*.gql',
  ],
  generates: {
    'gql/graphql.ts': {
      plugins: ['typescript', 'typescript-operations', 'typescript-generic-sdk'],
      config: {
          rawRequest: true,
          scalars: {
          BigInt: 'bigint|number',
          Date: 'string',
        },
      },
    },
  },
};

export default config;
  1. Update the GraphQL client in your fixture. Pass { rawResponse: true } to getClient:

fixtures/gql.ts

getClient(apiContext, { rawResponse: true });
  1. Use the raw response in your tests. The raw response will include both data and errors:

tests/example.test

import { test, expect } from '@fixtures/gql';

test('playwright-graphql test', async ({ gql }) => {
    const res = await gql.getCityByName({
        name: 'Lviv'
    });
    
    expect(res).toHaveProperty('data');
    expect(res).toHaveProperty('errors');
    res.data; // will have type raw schema.
})

Get Client signature

getClient(
  apiContext: APIRequestContext,
  options?: { gqlEndpoint?: string; rawResponse?: boolean },
  requestHandler?: (request: () => Promise<any>) => Promise<any>
);

Options:

Default values for options: { gqlEndpoint: '/api/graphql', rawResponse: false }

Set gqlEndpoint to customize graphql endpoint.

Set rawResponse to return { errors: any[], body: R } instead of R, R represents autogenerated return type from gql schema. This parameter can be used only when rawRequest: true is included in codegen.ts.

Request Handler Callback

You can inject custom logic before and after GraphQL API calls using a request handler callback:

import { getClient, GqlAPI } from '@gql';

const customRequestHandler = async (requester: () => Promise<APIResponse>) => {
  // Custom pre-call logic
  const res = await requester();
  // Custom post-call logic
  return res;
};

const gqlApiClient: GqlAPI = getClient(apiContext, { gqlEndpoint: '/api/graphql' }, customRequestHandler);

Custom operations

If you need to create custom operations for specific tests, you can modify the codegen.ts file to include additional paths for documents:

Steps to Add Custom Operations:

  1. Update the documents section in your codegen.ts file:
import type { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
  overwrite: true,
  schema: './schema.gql',
  documents: [
    'gql/autogenerated-operations/**/*.gql',
    'gql/custom-operations/**/*.gql',
  ],
  generates: {
    'gql/graphql.ts': {
      plugins: ['typescript', 'typescript-operations', 'typescript-generic-sdk'],
      config: {
        scalars: {
          BigInt: 'bigint|number',
          Date: 'string',
        },
      },
    },
  },
};

export default config;

Pay attention on addition item in documents: 'gql/custom-operations/**/*.gql' put you custom gql files under this directory.

  1. Add generated files and directories to .gitignore:
gql/autogenerated-operations
gql/**/*.ts
gql/**/*.js
  1. Regenerate types with custom operations.

Graphql explorer

You can use tools like Apollo Explorer to build and test custom queries or mutations interactively before adding them to your project.

GraphQL API call options

Each generated operation accepts an optional second parameter for additional configuration options. These options extend Playwright's post method method with two extra parameters:

  • returnRawJson Returns the full JSON payload instead of parsed data.
  • failOnEmptyData Prevents errors when the response contains no data (useful for error testing).

Here is how the second parameter type is declared.

type PlaywrightRequesterOptions = {
    returnRawJson?: boolean;
    failOnEmptyData?: boolean;
} & Omit<PostOptionsType, 'data'>;

Example Usage in Tests:

import { test, expect } from '@fixtures/gql';

test('playwright-graphql test with options', async ({ gql }) => {
  const res = await gql.getCityByName(
    { name: 'Lviv' },
    { returnRawJson: true }
  );

  expect(res).toHaveProperty('data');
});

Negative test cases

GraphQL responses often include an errors field instead of returning HTTP error codes like 400x or 500x. To verify errors in such cases, use the option failOnEmptyData.

Example Negative Test Case:

import { test, expect } from '@fixtures/gql';

test('playwright-graphql test negative', async ({ gql }) => {
    const res = await gql.getCityByName({
        name: 'Lviv'
    }, { failOnEmptyData: false });

    expect(res).toHaveProperty('errors[0].message');
})

GraphQL Coverage Reporting

GraphQL Coverage Reporting helps you track and visualize which GraphQL operations and their respective arguments are exercised by your tests. This feature not only covers simple queries and mutations but also handles complex input parameters (including nested types and enums) by presenting them in a clear, human-readable summary.

Generates a detailed log and an HTML summary report showing the coverage of your GraphQL operations: DEMO

Playwright config file for the GraphQL coverage reporter: 1. graphqlFilePath (required): Path to your autogenerated GraphQL file with types and getClient function (e.g. './gql/graphql.ts'). 2. coverageFilePath (optional): Path for the coverage log file. Default: ./gql-coverage.log. 3. htmlFilePath (optional): Path for the HTML summary report. Default: './gql-coverage.html'. 4. logUncoveredOperations (optional): Whether to log uncovered operations. Default: false. 5. minCoveragePerOperation (optional): Minimum coverage percentage required per operation. Default: 100. 6. saveGqlCoverageLog (optional): Whether to save the detailed coverage log. Default: false. 7. saveHtmlSummary (optional): Whether to save the HTML summary report. Default: false.

Below is a sample Playwright config using these options:

import { defineConfig } from '@playwright/test';

export default defineConfig({
    reporter: [
        ['list'],
        ['playwright-graphql/coverage-reporter', {
            graphqlFilePath: './gql/graphql.ts', 
            coverageFilePath: './coverage/gql-coverage.log',
            htmlFilePath: './coverage/gql-coverage.html',
            logUncoveredOperations: true,
            minCoveragePerOperation: 80,
            saveGqlCoverageLog: true,
            saveHtmlSummary: true
        }]
    ],
});

Environment Variable Override

If you need to change the default temporary directory where coverage log files are stored, set the environment variable process.env.PW_GQL_TEMP_DIR.

By default, the coverage logs are saved in a directory named .gql-coverage.

Integrating the Coverage Logger into Your GraphQL Client

To enable coverage tracking for your GraphQL requests add --coverage to playwright-graphql cli.

  • playwright-graphql --coverage

Template project: https://github.com/DanteUkraine/playwright-graphql-example

1.2.2

2 months ago

1.2.1

2 months ago

1.2.0

2 months ago

1.2.0-beta.10

2 months ago

1.2.0-beta.9

2 months ago

1.2.0-beta.8

2 months ago

1.2.0-beta.7

2 months ago

1.2.0-beta.6

2 months ago

1.2.0-beta.5

2 months ago

1.2.0-beta.4

2 months ago

1.2.0-beta.3

2 months ago

1.2.0-beta.2

2 months ago

1.2.0-beta.1

2 months ago

1.1.2

2 months ago

1.1.1

2 months ago

1.1.0

3 months ago

1.0.4

4 months ago

1.0.3

5 months ago

1.0.2

5 months ago

1.0.1

5 months ago

1.0.0

6 months ago

0.2.0

6 months ago

0.1.0

6 months ago

1.0.0-RC-2.2

6 months ago

1.0.0-RC-2.1

6 months ago

1.0.0-RC-1

6 months ago