This library provide playwright integration with graphql for efficient API tests.
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.
The build-in CLI simplifies code generation process to one simple command.
playwright-graphql --schema schema.gql
Template project: https://github.com/DanteUkraine/playwright-graphql-example
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
playwright-graphql --schema path-to-schema.gql
Will generate you next:
π Project Root
βββ π path-to-schema.gql (existing schema file)
βββ π gql (default directory for generated files)
βββπ path-to-schema (will become a name for related operation directory)
β βββ π 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:
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)
βββ π gql (default directory for generated files)
βββπ schema (each schema will have its own directory with operations)
β βββ π 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:
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.
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.
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.
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();
})
Designed for common workflow, the playwright-graphql CLI tool automates the process of generating GraphQL schemas, operations, and TypeScript types for your Playwright tests.
Use cases:
Basic client generation:
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'}"
The same header will be added to each schema introspect API call.
playwright-graphql -u http://localhost:4000/api/graphql -u http://localhost:4001/api/graphql -h "Authorization: Bearer common-token" -s schema1.gql -s schema2.gql
Different headers for each url requires splitting scripts:
playwright-graphql -u http://localhost:4000/api/graphql -h "Authorization: Bearer first-token" -s schema1.gql
playwright-graphql -u http://localhost:4001/api/graphql -h "Authorization: Bearer second-token" -s country.gql
Custom paths for generated files:
playwright-graphql --url http://localhost:4000/api/graphql --gqlDir generated/test-client --gqlFile my-api-client.ts
Using an existing schema file:
playwright-graphql --schema existing-schema.gql
Enabling coverage logging:
playwright-graphql --url http://localhost:4000/api/graphql --coverage
Custom operations without introspection:
playwright-graphql --url http://localhost:4000/api/graphql --introspect false --document src/operations
Using a custom codegen configuration:
playwright-graphql --custom --codegen path/to/codegen.ts
You can save codegen.ts
file for your combination:
playwright-graphql -u http://localhost:4000/api/graphql --saveCodegen
Generate multiple clients:
playwright-graphql -u http://localhost:4000/api/graphql -u http://localhost:4000/api/graphql -s schema1.gql -s schema2.gql
Generate multiple clients into custom output dir with custom file names:
playwright-graphql -s schema1.gql -s schema2.gqq -o ./apps/shell/e2e/gql/dgc-operations -d ./generated -f first-schema.ts -f second-schema.ts
Output:
π Project Root
βββ π schema1.gql
βββ π schema2.gql
βββ π gql
βββπ schema1
β βββ π autogenerated-operations
β βββ π mutations.gql
β βββ π queries.gql
βββπ schema2
β βββ π autogenerated-operations
β βββ π mutations.gql
β βββ π queries.gql
βββ π schema1.ts
βββ π schema2.ts
When you generate multiple clients and do not specify name for ts file with -f
, CLI will not reuse default name graphql.ts,
each client name will match schema name to make it clear.
Specify client names:
playwright-graphql -u http://localhost:4000/api/graphql -u http://localhost:4000/api/graphql -s schema1.gql -s schema2.gql -f gqlClient -f gqlApi
Output:
π Project Root
βββ π schema1.gql
βββ π schema2.gql
βββ π gql
βββπ schema1
β βββ π autogenerated-operations
β βββ π mutations.gql
β βββ π queries.gql
βββπ schema2
β βββ π autogenerated-operations
β βββ π mutations.gql
β βββ π queries.gql
βββ π gqlClient.ts
βββ π gqlApi.ts
Generate multiple clients with custom operations:
playwright-graphql -u http://localhost:4000/api/graphql -u http://localhost:4000/api/graphql -s schema1.gql -s schema2.gql -o ./schema1-operations, -o ./schema2-operations
Output:
π Project Root
βββ π schema1.gql
βββ π schema2.gql
βββ π schema1-operations
βββ π schema2-operations
βββ π gql
βββπ schema1
β βββ π autogenerated-operations
β βββ π mutations.gql
β βββ π queries.gql
βββπ schema2
β βββ π autogenerated-operations
β βββ π mutations.gql
β βββ π queries.gql
βββ π schema1.ts // this client will include operations from project root schema1-operations
βββ π schema2.ts // this client will include operations from project root schema2-operations
In case not all your clients need custom operations, for example only schema2 need custom operations change the order of args.
playwright-graphql -u http://localhost:4000/api/graphql -u http://localhost:4000/api/graphql -s schema2.gql -s schema1.gql -o ./schema2-operations
Output:
π Project Root
βββ π schema1.gql
βββ π schema2.gql
βββ π schema2-operations
βββ π gql
βββπ schema1
β βββ π autogenerated-operations
β βββ π mutations.gql
β βββ π queries.gql
βββπ schema2
β βββ π autogenerated-operations
β βββ π mutations.gql
β βββ π queries.gql
βββ π schema1.ts
βββ π schema2.ts // this client will include operations from project root schema2-operations
Document params will be added to lists of documents regarding order
To check details save codegen file and verify output of your command.
The CLI tool accepts several options to customize its behavior. Below is a summary of the available command-line parameters:
Option | Alias | Description | Type | Default |
---|---|---|---|---|
--url |
-u |
Full GraphQL endpoint URL(s) used for schema retrieval. In case this option is not passed, the script will skip schema generation and will look for an existing schema. | array | optional |
--schema |
-s |
Path to save the generated GraphQL schema file(s). If the URL option is not provided, the script expects that the schema already exists. | array | [schema.gql ] |
--header |
-h |
Optional authentication header(s) for schema fetching. Can be passed multiple times. | array | optional |
--gqlDir |
-d |
Path to save the auto-generated GraphQL files. | string | gql |
--gqlFile |
-f |
Path to save the auto-generated GraphQL type-safe client (you will import this into your code). | array | [graphql.ts ] |
--document |
-o |
Glob pattern(s) that will be added to documents. | array | optional |
--depthLimit |
Β | Defines the maximum depth of nested fields to include in the generated GraphQL queries. | number | optional |
--introspect |
-i |
Turns off auto-generation of operations. | boolean | true |
--raw |
Β | Generates GraphQL client witch return raw responses. | boolean | false |
--codegen |
-c |
Path to save the codegen config. | string | codegen.ts |
--saveCodegen |
Β | Save generated codegen file. | boolean | false |
--custom |
Β | Generation will be done from your custom codegen file. No autogenerated operation. | boolean | false |
--coverage |
Β | Flag to add coverage logger to auto-generated client. | boolean | false |
--silent |
Β | Suppress all logs. | boolean | false |
--version |
Β | Print version. | Β | Β |
--help |
Β | Print all CLI options. | Β | Β |
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:
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;
{ rawResponse: true }
to getClient
:fixtures/gql.ts
getClient(apiContext, { rawResponse: true });
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.
})
getClient(
apiContext: APIRequestContext,
options?: { gqlEndpoint?: string; rawResponse?: boolean },
requestHandler?: (request: () => Promise<any>) => Promise<any>
);
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
.
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);
Collect your custom operations under any directory in your project and pass it to CLI.
playwright-graphql --url http://localhost:4000/api/graphql -o src/operations
That will build your client with autogenerated and your custom operations.
To use only your custom operations add introspect flag -i false
.
playwright-graphql --url http://localhost:4000/api/graphql -o src/operations -i false
You can use tools like Apollo Explorer to build and test custom queries or mutations interactively before adding them to your project.
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');
});
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 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:
Playwright config file for the GraphQL coverage reporter:
./gql-coverage.log
.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
}]
],
});
In case you generate multiple clients each client coverage reporter has to be specified separately.
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