# TestModule

The `TestModule` class represents a single module in a single project. This class is only available in the main thread. Refer to the ["Runner API"](/api/advanced/runner#tasks) if you are working with runtime tasks.

The `TestModule` instance always has a `type` property with the value of `module`. You can use it to distinguish between different task types:

```ts
if (task.type === 'module') {
  task // TestModule
}
```

::: warning Extending Suite Methods
The `TestModule` class inherits all methods and properties from the [`TestSuite`](/api/advanced/test-suite). This guide will only list methods and properties unique to the `TestModule`.
:::

## moduleId

This is usually an absolute unix file path (even on Windows). It can be a virtual id if the file is not on the disk. This value corresponds to Vite's `ModuleGraph` id.

```ts
'C:/Users/Documents/project/example.test.ts' // ✅
'/Users/mac/project/example.test.ts' // ✅
'C:\\Users\\Documents\\project\\example.test.ts' // ❌
```

## relativeModuleId

Module id relative to the project. This is the same as `task.name` in the deprecated API.

```ts
'project/example.test.ts' // ✅
'example.test.ts' // ✅
'project\\example.test.ts' // ❌
```

## viteEnvironment <Version>4.1.0</Version> {#viteenvironment}

This is a Vite's [`DevEnvironment`](https://vite.dev/guide/api-environment) that transforms all files inside of the test module.

::: details History
- `v4.0.15`: added as experimental
:::

## state

```ts
function state(): TestModuleState
```

Works the same way as [`testSuite.state()`](/api/advanced/test-suite#state), but can also return `queued` if module wasn't executed yet.

## meta <Version>3.1.0</Version> {#meta}

```ts
function meta(): TaskMeta
```

Custom [metadata](/api/advanced/metadata) that was attached to the module during its execution or collection. The meta can be attached by assigning a property to the `task.meta` object during a test run:

```ts {5,10}
import { test } from 'vitest'

describe('the validation works correctly', (task) => {
  // assign "decorated" during collection
  task.file.meta.decorated = false

  test('some test', ({ task }) => {
    // assign "decorated" during test run, it will be available
    // only in onTestCaseReady hook
    task.file.meta.decorated = false
  })
})
```

:::tip
If metadata was attached during collection (outside of the `test` function), then it will be available in [`onTestModuleCollected`](./reporters#ontestmodulecollected) hook in the custom reporter.
:::

## diagnostic

```ts
function diagnostic(): ModuleDiagnostic
```

Useful information about the module like duration, memory usage, etc. If the module was not executed yet, all diagnostic values will return `0`.

```ts
interface ModuleDiagnostic {
  /**
   * The time it takes to import and initiate an environment.
   */
  readonly environmentSetupDuration: number
  /**
   * The time it takes Vitest to setup test harness (runner, mocks, etc.).
   */
  readonly prepareDuration: number
  /**
   * The time it takes to import the test module.
   * This includes importing everything in the module and executing suite callbacks.
   */
  readonly collectDuration: number
  /**
   * The time it takes to import the setup module.
   */
  readonly setupDuration: number
  /**
   * Accumulated duration of all tests and hooks in the module.
   */
  readonly duration: number
  /**
   * The amount of memory used by the module in bytes.
   * This value is only available if the test was executed with `logHeapUsage` flag.
   */
  readonly heap: number | undefined
  /**
   * The time spent importing every non-externalized dependency that Vitest has processed.
   */
  readonly importDurations: Record<string, ImportDuration>
  /**
   * The id of the worker that ran this file. This value cannot be higher than `maxWorkers`.
   * If file did not run yet, this will be 0.
   *
   * **Warning**: Node.js tests and browser tests run in different pools and do not share `concurrencyId`.
   * It is possible to have multiple modules with the same `concurrencyId` because of that.
   * Use `project.isBrowserEnabled()` to distinguish the concurrency.
   */
  readonly concurrencyId: number
  /**
   * Incremental number of the worker that ran this file. This number increases with each worker.
   * If file did not run yet, this will be 0.
   *
   * **Warning**: Node.js tests and browser tests run in different pools and do not share `workerId`.
   * It is possible to have multiple modules with the same `workerId` because of that.
   * Use `project.isBrowserEnabled()` to distinguish the concurrency.
   */
  readonly workerId: number
}

/** The time spent importing & executing a non-externalized file. */
interface ImportDuration {
  /** The time spent importing & executing the file itself, not counting all non-externalized imports that the file does. */
  selfTime: number

  /** The time spent importing & executing the file and all its imports. */
  totalTime: number
}
```

## logs <Version>5.0.0</Version> {#logs}

```ts
function logs(): ReadonlyArray<UserConsoleLog>
```

Console logs recorded on top level of the module during test collection. For example:

```ts
console.log('included') // [!code highlight]

describe('suite', () => {
  console.log('not included') // [!code error]

  test('test', () => {
    console.log('not included') // [!code error]
  })
})
```

## toTestSpecification <Version>4.1.0</Version> {#totestspecification}

```ts
function toTestSpecification(testCases?: TestCase[]): TestSpecification
```

Returns a new [test specification](/api/advanced/test-specification) that can be used to filter or run this specific test module.

It accepts an optional array of test cases that should be filtered.
