A pytest plugin for end-to-end testing of language servers


Keywords
devtools, language-server-protocol, pytest-plugin
License
MIT
Install
pip install pytest-lsp==0.4.2

Documentation

LSP Devtools

pre-commit.ci status

This repo is an attempt at building the developer tooling I wished existed when I first started working on Esbonio.

This is a monorepo containing a number of sub-projects.

lib/lsp-devtools - A grab bag of development utilities

PyPIPyPI - DownloadsLicense: MIT

TUI Screenshot

A collection of cli utilities aimed at aiding the development of language servers and/or clients.

  • agent: Used to wrap an lsp server allowing messages sent between it and the client to be intercepted and inspected by other tools.
  • record: Connects to an agent and record traffic to file, sqlite db or console. Supports filtering and formatting the output
  • inspect: A browser devtools inspired TUI to visualise and inspecting LSP traffic. Powered by textual
  • client: Experimental A TUI language client with built in inspect panel. Powered by textual

lib/pytest-lsp - End-to-end testing of language servers with pytest

PyPIPyPI - DownloadsLicense: MIT

pytest-lsp is a pytest plugin for writing end-to-end tests for language servers.

It works by running the language server in a subprocess and communicating with it over stdio, just like a real language client. This also means pytest-lsp can be used to test language servers written in any language - not just Python.

pytest-lsp relies on the pygls library for its language server protocol implementation.

import sys

import pytest_lsp
from lsprotocol.types import (
    CompletionParams,
    InitializeParams,
    Position,
    TextDocumentIdentifier,
)
from pytest_lsp import (
    ClientServerConfig,
    LanguageClient,
    client_capabilities,
)


@pytest_lsp.fixture(
    config=ClientServerConfig(
        server_command=[sys.executable, "-m", "esbonio"],
    ),
)
async def client(lsp_client: LanguageClient):
    # Setup
    response = await lsp_client.initialize_session(
        InitializeParams(
            capabilities=client_capabilities("visual-studio-code"),
            root_uri="file:///path/to/test/project/root/",
        )
    )

    yield

    # Teardown
    await lsp_client.shutdown_session()


async def test_completion(client: LanguageClient):
    result = await client.text_document_completion_async(
        params=CompletionParams(
            position=Position(line=5, character=23),
            text_document=TextDocumentIdentifier(
                uri="file:///path/to/test/project/root/test_file.rst"
            ),
        )
    )

    assert len(result.items) > 0