# graphql-integration

Package providing utilities for assisting with GraphQL integration tests. The goal of this package is to reduce boilerplate code
in gql integration tests by centralizing the most commonly used functionality.

## Usage

This package is built to simplify the process of writing integration tests for GraphQL services. It provides a graphQL client
to execute queries and mutations.

```typescript
import { GraphQLClient } from '@theorchard/graphql-integration';

describe('getVendorFeatures', () => {
    describe('when vendor exists', () => {
        let response: VendorFeaturesQuery;

        beforeAll(async () => {
            const variables = { vendorId: 6971 };
            const graphQLClient = new GraphQLClient(QUERIES_PATH);
            response = await graphQLClient.executeQuery({
                query: 'VendorFeatures',
                variables,
                headers: {
                    ...TEST_USER_HEADERS,
                },
            });
        });
    });
});
```

The client requires the path of your queries directory relative to your test file.

### Environment Variables

The class supports the use of environment variables to configure the gql url and port.
These variables are `BASE_URL` and `PORT`. If these are not set, the class will default to using localhost port 8080.

## Wiring it up in a subgraph

A typical Apollo Federation subgraph (e.g. `graphql-account`) wires the two CLIs into its
`package.json` scripts so codegen and coverage run alongside the existing test commands.

Assuming the layout in [Project Structure](#project-structure):

```
src/schema/         # SDL (one or more *.graphql files)
tests/queries/      # integration test query documents
tests/generated/    # generated TS types (gitignored)
tests/specs/        # *.spec.ts files using GraphQLClient
```

Add the two binaries to your subgraph's `package.json`:

```json
{
    "scripts": {
        "generate:types": "graphql-codegen && graphql-integration-codegen src/schema tests/generated/index.ts tests",
        "test:integration": "vitest run --project integration && pnpm test:integration:coverage",
        "test:integration:coverage": "graphql-integration-coverage src/schema tests/queries --no-fail"
    },
    "devDependencies": {
        "@theorchard/graphql-integration": "^2.3.0"
    }
}
```

What each script does:

-   `generate:types` — runs the resolver codegen (`graphql-codegen`) and then
    `graphql-integration-codegen` to produce typed query/mutation operations under
    `tests/generated/index.ts`. Re-run after any schema or query change.
-   `test:integration` — runs the integration spec suite, then prints the coverage report.
-   `test:integration:coverage` — standalone target so the report can be regenerated
    without re-running the suite. Drop `--no-fail` if you want CI to fail on uncovered fields.

### Codegen CLI

```bash
Usage: graphql-integration-codegen [options] <schema> <output> [documents]

CLI tool for generating GraphQL types for integration tests

Arguments:
  schema      Path to GraphQL schema
  output      Path to output file (e.g., src/generated/types.ts)
  documents   Path to GraphQL documents (optional)

Options:
  -h, --help  display help for command
```

### Coverage CLI

Walks your schema and your integration query documents and reports which type/field
combinations are exercised. For federated subgraphs, types declared with `@key` also get a
synthetic `__resolveReference` row that's credited whenever a test query selects
`_entities(representations: $r) { ... on Foo { ... } }` with that type condition.

```bash
Usage: graphql-integration-coverage [options] <schema> <queries>

Report which schema fields are exercised by integration test queries

Arguments:
  schema       Path to GraphQL schema directory
  queries      Path to GraphQL integration query documents

Options:
  --all        Show every field, not just uncovered ones
  --no-summary Skip the per-type coverage summary table
  --no-fail    Always exit 0, even when uncovered fields exist
  -h, --help   display help for command
```

Output is three sections:

1. **Uncovered fields** — a table of type/field pairs with zero hits.
2. **Coverage percentage by type** — covered/total/percent per type, sorted worst-first.
3. **Overall coverage** — single line with the aggregate percentage.

The same logic is exposed programmatically for use inside a test runner:

```typescript
import {
    computeCoverage,
    printCoverageSummary,
    printCoverageTable,
    summarizeCoverage,
} from '@theorchard/graphql-integration';

const report = computeCoverage({
    schemaPath: 'src/schema',
    queriesPath: 'tests/queries',
});

printCoverageTable(report);
printCoverageSummary(report);

const { overall } = summarizeCoverage(report);
if (overall.percent < 80) {
    throw new Error(`Coverage ${overall.percent.toFixed(2)}% is below the 80% threshold`);
}
```

## Project Structure

The recommended project structure for your integration tests:

```/
├── tests/
│   ├── constants.ts
│   ├── queries/
│   │   ├── exampleQuery.graphql
│   └── specs/
│       ├── exampleQuery.spec.ts
```

Spec files should be `.spec.ts` extensions

## A Note On JWT Tokens

Our permissions platform patterns require JWT tokens to be passed in the authorization header for most requests.
To generate these tokens, please use the package and patterns detailed in
https://github.com/theorchard/backend-js-packages/tree/master/packages/backend-jwtauth-testing

This package provides utilities to generate JWT tokens for testing purposes. You can then pass the token in the headers of the request.
