Can't override types with Nightwatch versions that added ts-node support
Description of the bug/issue
When I use nightwatch.d.ts to extend Nightwatch types I expect to be able to use those types during test runtime
In versions of Nightwatch prior to adding direct .ts file execution (ts-node) I could create a nightwatch.d.ts file in my tests directory to make available custom commands on NightwatchBrowser. For example,
// nightwatch.d.ts
declare module "nightwatch" {
export interface NightwatchCustomCommands {
helloWorld(): Awaitable<NightwatchAPI>;
}
}
// myTestFile.ts
'hello world test': async (browser: NightwatchBrowser) => {
browser.helloWorld(); // would not give me any errors about the property not existing on Nightwatch browser
}
But in newer versions of Nightwatch when I try to execute the tests it attempts to load the nightwatch.d.ts file which causes this error
┌ ────────────────── ✖ local: nightwatch.d.ts ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ │
│ ✖ TypeError │
│ Unable to require file: tests/nightwatch.d.ts │
│ This is usually the result of a faulty configuration or import. Make sure there is a `.js`, `.json` or other executable extension with loader attached before `ts-node` available. │
│ Stack Trace : │
│ at getOutput (redacted/node_modules/ts-node/src/index.ts:1085:17) │
│ at Object.compile (redacted/node_modules/ts-node/src/index.ts:1433:41) │
│ at Module.m._compile (redacted/node_modules/ts-node/src/index.ts:1617:30) │
│ at Module._extensions..js (node:internal/modules/cjs/loader:1180:10) │
│ at Object.require.extensions.<computed> [as .ts] (redacted/node_modules/ts-node/src/index.ts:1621:12) │
│ at Module.load (node:internal/modules/cjs/loader:1004:32) │
│ at Function.Module._load (node:internal/modules/cjs/loader:839:12) │
│ at Module.require (node:internal/modules/cjs/loader:1028:19) │
│ at require (node:internal/modules/cjs/helpers:102:18) │
│ at Function.module.exports [as requireModule] (/redactednode_modules/nightwatch/lib/utils/requireModule.js:4:16) │
Followed by
┌ ────────────────── ✖ local: helloWorldTest.ts ──────────────────────────────────────────────────────────────────────────┐
│ │
│ TSError │
│ ⨯ Unable to compile TypeScript: │
│ tests/helloWorldTest.ts(10,38): error TS2339: Property 'helloWorld' does not exist on type 'NightwatchBrowser'. │
│ │
│ │
│ │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Steps to reproduce
- Create a
nightwatch.d.tsfile to add types not part of@types/nightwatchand put it inside your tests folder
// nightwatch.d.ts
declare module "nightwatch" {
export interface NightwatchCustomCommands {
helloWorld(): Awaitable<NightwatchAPI>;
}
}
- In your test IDE those commands should be available in the intellisense, but if you try to execute the test using
nightwatch --test yourTestHere.tsit will complain thatProperty 'helloWorld' does not exist on type 'NightwatchBrowser'.
// myTestFile.ts
'hello world test': async (browser: NightwatchBrowser) => {
browser.helloWorld(); // IDE will not give me any errors about the property not existing on Nightwatch browser
}
If you try to run all your tests you'll notice Nightwatch tries to execute the nightwatch.d.ts file as a test as well.
If I go back to the older style of using tsc to transpile everything to .js in a separate test directory everything works fine still. It would be nice to leverage the direct execution capability while retaining the ability to extend/override the built in types to allow use of custom commands not part of the @types/nightwatch definitions
Sample test
No response
Command to run
No response
Verbose Output
No response
Nightwatch Configuration
No response
Nightwatch.js Version
2.6.4
Node Version
16.17.1
Browser
No response
Operating System
Mac
Additional Information
No response
Hi, thanks for raising this issue.
For extending the types in Nightwatch, you can have a project structure like the following:
my-project/
|-- nightwatch/
| |-- tsconfig.json
|-- test/
| |-- myTest.ts
|-- types/
| |-- nightwatch.d.ts
|-- tsconfig.json
|-- package.json
Now, suppose your test file is as follows:
// test/myTest.ts
import { NightwatchBrowser, NightwatchTests } from "nightwatch";
const Test: NightwatchTests = {
'hello world test': async (browser: NightwatchBrowser) => {
browser.helloWorld();
}
}
export default Test;
You can create a types/nightwatch.d.ts file as below:
// types/nightwatch.d.ts
import 'nightwatch';
declare module "nightwatch" {
interface NightwatchCustomCommands {
helloWorld(): Awaitable<NightwatchAPI, unknown>;
}
}
After creating the above file, the types for your custom command should start to appear in your tests. But if they don't, go to tsconfig.json file present in the root of your project, and add "files" and "include" properties to it:
// tsconfig.json
{
"compilerOptions": {
// all configs here
},
"files": ["./types/nightwatch.d.ts"], // path to the recently created nightwatch.d.ts file.
"include": ["test", "nightwatch"] // directories in which your nightwatch tests are present, where the above type declaration file should be applied.
}
Also, make sure your nightwatch/tsconfig.json extends the root tsconfig.json so that the above added properties are auto-applied in there:
// nightwatch/tsconfig.json
{
"extends": "../tsconfig",
"compilerOptions": {
// all configs here
},
"include": ["."]
}
Your project should run fine after following the above instructions.
Few additional notes:
- If
ts-nodeis still trying to run yournightwatch.d.tsfile, you can use theexcludeproperty in yournightwatch/tsconfig.jsonfile, like below:{ "extends": "../tsconfig", "compilerOptions": { // all configs here }, "include": ["."], "exclude": ["**/*.d.ts"] }
This worked. I had to add the /nightwatch/globals/* and /nightwatch/commands to the exclude path, those contain .js files, to prevent a VS Code warning inside the tsconfig.json json about [files in there] will be overwritten.