In this post I will show how you can write end-to-end tests in TypeScript and how to import from test code your application source files using path aliases like this:
1 | import {greeting} from '@app/greeting' |
instead of brittle relative paths like this
1 | import {greeting} from '../../app/src/greeting' |
Note: the source code for this blog post is at bahmutov/using-ts-aliases-in-cypress-tests
Application
For this demo I will use a minimal example: just an HTML page index.html with some TypeScript code
1 | <html> |
The code src/app.ts places the greeting imported from src/utils.ts into the DOM
1 | export const greeting = 'Hello World' |
1 | import { greeting } from "./utils" |
To serve the app I will use Parce bundler
1 | npm i -D parcel-bundler |
1 | { |
When I run npm start the page is working as expected at localhost:1234

Cypress Tests in TypeScript
We can add Cypress end-to-end tests to this project with
1 | npm i -D cypress |
To quickly scaffold everything, I prefer to use my little utility @bahmutov/cly which stands for "quickly". Or maybe it stands for "Cypress CLI"? Who knows.
1 | $ npx @bahmutov/cly init |
We have cypress.json and cypress folder, let's change the contents of cypress/integration/spec.js to test our page.
1 | /// <reference types="Cypress" /> |
Start the app in one terminal with npm start and open Cypress from another terminal with npx cypress open - the test should be green.

But if we write our application in TypeScript, let's also write our tests in TypeScript. The simplest way to configure test bundling is by installing @bahmutov/add-typescript-to-cypress package. We also need to install TypeScript module itself, and we need Webpack
1 | npm install --save-dev @bahmutov/add-typescript-to-cypress typescript webpack |
Super, it even has created a default tsconfig.json file for us
1 | { |
We can rename our test file from spec.js to spec.ts - and it should run the same. Since the tsconfig.json file is only necessary for our Cypress tests I will move it into the cypress folder. Do not forget to update the paths in tsconfig.json after moving.
Our application shows the greeting text - and I don't want to hardcode the string to find in my test code. Instead I think it is ok to load the greeting from the application code. It is simple to do using a relative path.
1 | import {greeting} from '../../src/utils' |
Nice, but I really dislike the long relative paths that use ../.. to get out of the Cypress integration folder. Luckily TypeScript and Webpack both have ways to define aliases to use shortcuts. We need TypeScript path aliases to make sure our TypeScript tooling (like VSCode IntelliSense) understands the spec files, while Webpack aliases are needed to find the code during bundling.
Our goal is to refer to all source files by @src/... from our spec files rather than ../../src/....
In the cypress/tsconfig.json add baseUrl and paths properties.
1 | { |
Nice, now we can import greeting from the test file like this
1 | import {greeting} from '@src/utils' |
VSCode can resolve the alias correctly, as shown by this popup

But if we try to run Cypress test right now, we will get a nasty error
1 | ./cypress/integration/spec.ts |
This is due to the fact that Webpack bundler does not know about the path aliases in tsconfig.json. The simplest way is to tell Webpack how to alias modules by prefix. In file cypress/plugins/cy-ts-preprocessor.js add the following alias object to the existing resolve block:
1 | const webpackOptions = { |
That is it, our tests can share code with application without fragile folder hops.