Astro Test Utils
Astro’s current ecosystem lacks solutions for testing integrations, adapters, and components without either copying internal entire parts of the Astro code or bypassing package encapsulation to import internal modules from Astro. This tool aims to fill that gap by providing high-level wrapper over the known practices required to test Astro libraries.
It offers utilities for setting up environments, running builds, and inspecting renders, ensuring compatibility and performance without the need to tamper with internal Astro logic.
Compatibility
Section titled “Compatibility”Relying on internal details of Astro can lead to your code breaking at any time. Those internal pieces can move, break or be removed from Astro even on patch versions since they are not part of the public API.
Although this library also utilizes some parts of the Astro code that are meant to be internal, projects using this library for their tests will not break in case those parts are changed. This is ensured by how it built and published, although the source code breaks encapsulation, the code in the published library relies only on Astro’s public API.
You can check on your node_modules
directory to see it 😉
There is an ongoing discussion about having this in the Astro core repo to be published under @astrojs/
.
This package is published as a milestone in that effort. It is also a necessity to test all other packages that are part of Inox Tools until this proposal lands on Astro core. If/when that happens, this package will be published as a thin wrapper around the official test package and deprecated.
If the conversations ends in the decision of not having a test package provided from Astro itself, then this package will continue to work for that purpose.
How to install
Section titled “How to install”npm i -D @inox-tools/astro-tests
pnpm add -D @inox-tools/astro-tests
yarn add -D @inox-tools/astro-tests
Fixtures
Section titled “Fixtures”config
Section titled “config”Type: AstroConfig
The final config passed to Astro’s programatic CLI entrypoints. This configuration can be overridden for each method call. It will automatically be passed to the following methods:
startDevServer
Section titled “startDevServer”Type: (inlineConfig:
AstroInlineConfig
) => Promise<DevServer>
Starts a development server on an available port.
This server cannot run simultaneously with .preview()
for the same fixture, as they share ports.
Ensure devServer.stop()
is called before the test exits.
Equivalent to running astro dev
.
Type: (inlineConfig:
AstroInlineConfig
) => Promise<void>
Builds into current folder (will erase previous build).
Equivalent to running astro build
.
buildWithCli
Section titled “buildWithCli”Type: () => Promise<import("node:child_process").ChildProcess>
Builds using the CLI’s astro build
command in a child process.
This method runs the build in a separate process, bypassing the programmatic API. It doesn’t accept configuration parameters since it uses the project’s configuration files directly.
While not an ideal solution for most testing scenarios, this can be useful in specific cases when testing libraries and integrations that behave differently when built using the programmatic build compared to using the CLI, which seems to be particularly more evident in CI environments.
This method is equivalent to running astro build
in a shell directly from your project’s root.
preview
Section titled “preview”Type: (inlineConfig:
AstroInlineConfig
) => Promise<PreviewServer>
Starts a preview server.
This server cannot run simultaneously with .dev()
on the same fixture, as they share ports.
Ensure server.stop()
is called before the test exits.
Equivalent to running astro preview
.
Type: (inlineConfig:
AstroInlineConfig
) => Promise<void>
Synchronizes the Astro project and configuration with the generated code, populating the src/env.d.ts
file and the .astro
directory.
Equivalent to running astro sync
.
Type: () => Promise<void>
Deletes the generated files from the fixture directory. Specifically, it deletes:
- The output directory (
outDir
config) - The cache directory (
cacheDir
config) - The
.astro
directory generated in the project - the
.astro
directory generated in thenode_modules
resolveUrl
Section titled “resolveUrl”Type: (url: string) => string
Resolves a relative URL to the full url of the running server.
This can only be called after either .startDevServer()
or .preview()
is called.
Type: (url: string, opts?:
RequestInit
) => Promise<
Response
>
Send a request to the given URL. If the URL is relative, it will be resolved relative to the root of the server (without a base path).
This can only be called after either .startDevServer()
or .preview()
is called.
pathExists
Section titled “pathExists”Type: (path: string) => boolean
Checks whether the given path exists on the build output (outDir
config).
readFile
Section titled “readFile”Type: (path: string) => Promise<string | null>
Read a file from the build (relative to the outDir
config). Returns null if the file doesn’t exist.
readSrcFile
Section titled “readSrcFile”Type: (path: string) => Promise<string | null>
Read a file from the project (relative to the root
config). Returns null if the file doesn’t exist.
editFile
Section titled “editFile”Type: (path: string, updater: string | null | ((content: string | null) => string | null)) => Promise<() => void>
Edit a file in the fixture directory.
The first parameter is a path relative to the root of the fixture.
The second parameter can be the new content of the file or a function that takes the current content and returns the new content. The content passed to the function will be null if the file doesn’t exist.
If the given content or content returned from the given function is null, the file will be deleted.
This function returns a Promise that resolves to another function. This resolved function can be called to revert the changes.
All changes made with editFile
are automatically reverted before the process exits.
resetAllFiles
Section titled “resetAllFiles”Type: () => void
Reset all changes made with .editFile()
readdir
Section titled “readdir”Type: (path: string) => Promise<string[]>
Read a directory from the build output (relative to outDir
config).
This is a convenience wrapper for readdir from Node’s FS Promise API.
Type: (pattern: string) => Promise<string[]>
Find entries in the build output matching the glob pattern.
The glob syntax used is from fast-glob
.
loadNodeAdapterHandler
Section titled “loadNodeAdapterHandler”Type: () => Promise<(req:
http.IncomingMessage
, res:
http.ServerResponse
) => void>
Load the handler for an app built using the Node Adapter.
The handler is the same as a listener for the request
event from Node’s native HTTP module.
loadTestAdapterApp
Section titled “loadTestAdapterApp”Type: () => Promise<TestApp>
TestApp
Section titled “TestApp”type TestApp = { render: (req: Request) => Promise<Response>; toInternalApp: () => App;};
A minimal proxy for the underlying Astro app, provided by the test adapter.
render
Section titled “render”Renders a Response
from the given Request
.
toInternalApp
Section titled “toInternalApp”Returns the underlying Astro App.
This class is internal, undocumented and highly unstable. Use it at your own risk.
Test Adapter
Section titled “Test Adapter”An Astro Adapter that exposes the rendering process to be called directly.
It also collects information about the build passed to the adapter to be inspected.
None of the options are required.
Type: Record<string, string | undefined>
Server-side environment variables to be used by astro:env
.
setRoutes
Section titled “setRoutes”Type: (routes:
RouteData
[]) => Promise<void>
A callback function that will receive the final value of the project routes.
Utilities
Section titled “Utilities”No Node checker
Section titled “No Node checker”A Vite plugin that ensures no module in the final bundle depends on built-in Node modules.
If any reference to a Node module is found in the generated bundle, the build will fail.
The checked modules are those from the built-in module list provided as part of node:modules
, both with an without the node:
prefix, as well as the prefix-only modules.
License
Section titled “License”Astro Test Utils is available under the MIT license.