Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(testing): add more content #177

Merged
merged 1 commit into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/orm/annotations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ null before running your model `create()`, `createMany()`,
public deletedAt: Date
```

:::warn
:::warning

The value set to `defaulTo` property will only be used when
the value for the specified column was not provided when calling
Expand Down
124 changes: 113 additions & 11 deletions docs/testing/cli-tests.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ For example, take a look at the e2e test defined below:

```typescript
import { Test, type Context } from '@athenna/test'
import { BaseConsoleTest } from '@athenna/core/testing/BaseConsoleTest'

export default class ExampleTest {
export default class ExampleTest extends BaseConsoleTest {
@Test()
public async 'test successful output'({ command }: Context) {
const output = await command.run('app')
Expand All @@ -35,6 +36,11 @@ output should have a successful exit code (`0`). In addition
to this simple assertion, Athenna also contains a variety of
assertions for inspecting the output.

You might have noticed that the `ExampleTest` is extending the
`BaseConsoleTest` class. We gonna see later on this documentation
what is the purpose of this class, and how to configure it for your
needs.

## Registering `command` plugin

The `command` property in your test context will only be
Expand All @@ -47,15 +53,15 @@ Just call the `Runner.addPlugin()` static method to set up
the request plugin imported from `@athenna/artisan/testing/plugins`:

```typescript title="Path.bootstrap('test.ts')"
import { Runner } from '@athenna/test'
import { request } from '@athenna/http/testing/plugins'
import { command } from '@athenna/artisan/testing/plugins'
import { Runner, assert, specReporter } from '@athenna/test'

await Runner.setTsEnv()
.addPlugin(assert())
.setAppEnv('test')
.addAssertPlugin()
.addPlugin(request())
.addPlugin(command()) 👈
.addReporter(specReporter())
.addPath('tests/e2e/**/*.ts')
.addPath('tests/unit/**/*.ts')
.setCliArgs(process.argv.slice(2))
Expand All @@ -75,8 +81,9 @@ that allow you to inspect your application's CLI output:

```typescript
import { Test, type Context } from '@athenna/test'
import { BaseConsoleTest } from '@athenna/core/testing/BaseConsoleTest'

export default class ExampleTest {
export default class ExampleTest extends BaseConsoleTest {
@Test()
public async testBasicCommand({ command }: Context) {
const output = await command.run('greet')
Expand All @@ -98,17 +105,17 @@ used to test your commands. To do so, you can call the
your tests:

```typescript title="Path.bootstrap('test.ts')"
import { Runner } from '@athenna/test'
import { request } from '@athenna/http/testing/plugins'
import { command, TestCommand } from '@athenna/artisan/testing/plugins'
import { Runner, assert, specReporter } from '@athenna/test'

TestCommand.setArtisanPath(Path.fixtures('artisan.ts')) 👈

await Runner.setTsEnv()
.addPlugin(assert())
.setAppEnv('test')
.addAssertPlugin()
.addPlugin(request())
.addPlugin(command())
.addReporter(specReporter())
.addPath('tests/e2e/**/*.ts')
.addPath('tests/unit/**/*.ts')
.setCliArgs(process.argv.slice(2))
Expand All @@ -128,8 +135,9 @@ this kind of customization in your tests:
```typescript
import { Config } from '@athenna/config'
import { Test, type Context } from '@athenna/test'
import { BaseConsoleTest } from '@athenna/core/testing/BaseConsoleTest'

export default class ExampleTest {
export default class ExampleTest extends BaseConsoleTest {
@Test()
public async testConfigCommand({ command }: Context) {
Config.set('app.name', 'MyAppName')
Expand Down Expand Up @@ -161,8 +169,9 @@ Now, we can use this new `artisan` file to run our command:
```typescript
import { Path } from '@athenna/common'
import { Test, type Context } from '@athenna/test'
import { BaseConsoleTest } from '@athenna/core/testing/BaseConsoleTest'

export default class ExampleTest {
export default class ExampleTest extends BaseConsoleTest {
@Test()
public async testConfigCommand({ command }: Context) {
const output = await command.run('greet', {
Expand All @@ -174,6 +183,32 @@ export default class ExampleTest {
}
```

### Changing Artisan file path for the test group

If you need to use the same Artisan file for all the tests inside
of your class, but you don't want to change it globally for all
the rest of your classes using `TestCommand.setArtisanPath()` method,
you can set the `artisanPath` property in your test class that
`BaseConsoleTest` will automatically change it when bootstraping
your app:

```typescript
import { Path } from '@athenna/common'
import { Test, type Context } from '@athenna/test'
import { BaseConsoleTest } from '@athenna/core/testing/BaseConsoleTest'

export default class ExampleTest extends BaseConsoleTest {
public artisanPath = Path.fixtures('consoles/artisan-set-app-name.ts') 👈

@Test()
public async testConfigCommand({ command }: Context) {
const output = await command.run('greet')

output.assertLogged('Hello from MyAppName!') ✅
}
}
```

## Debugging outputs

After executing a test command to your application,
Expand All @@ -182,8 +217,9 @@ inside with all the `output` data:

```typescript
import { Test, type Context } from '@athenna/test'
import { BaseConsoleTest } from '@athenna/core/testing/BaseConsoleTest'

export default class ExampleTest {
export default class ExampleTest BaseConsoleTest {
@Test()
public async testBasicCommand({ command }: Context) {
const output = await command.run('basic')
Expand Down Expand Up @@ -282,3 +318,69 @@ argument:
output.assertLogMatches(/Hello World/, 'stdout') // or stderr
output.assertLogNotMatches(/Hello World/, 'stdout') // or stderr
```

## The `BaseConsoleTest` class

The `BaseConsoleTest` class is responsible to bootstrap your Athenna
application **before running all** tests and also to kill the
application **after running all** tests, meaning that is not possible
to use the `command` property without extending this class or at least
setting up your own Athenna application using `Ignite` class.

If for some reason you need to change the options set when
calling the `Ignite.load()` or `Ignite.artisan()` methods,
you can set the `igniteOptions` and `artisanOptions` properties
in your test class:

```typescript
import { Path } from '@athenna/common'
import { type IgniteOptions } from '@athenna/core'
import { Test, type Context } from '@athenna/test'
import { BaseConsoleTest } from '@athenna/core/testing/BaseConsoleTest'

export default class ExampleTest extends BaseConsoleTest {
public igniteOptions: IgniteOptions = {
bootLogs: true,
shutdownLogs: true,
envPath: Path.fixtures('envs/.env'),
athennaRcPath: Path.fixtures('rcs/.athennarc.json'),
environments: ['http', 'test']
}

@Test()
public async 'test successful output'({ command }: Context) {
const output = await command.run('app')

output.assertSucceeded()
}
}
```

:::warning

Remember that changes done to the options of `Ignite` class will only
be relevant when running commands outside of the child process. Meaning
that if you call `command.run()`, the options used to ignite Artisan will
be from your Artisan file, and not from the ones you set in your test class.

To solve this, check how to change the [Artisan file path of your
test group](/docs/testing/cli-tests#changing-artisan-file-path-for-the-test-group).

:::

### Accessing `Ignite` instance

You are able to access the `Ignite` instance by using the `ignite`
property:

```typescript
import { Test, type Context } from '@athenna/test'
import { BaseConsoleTest } from '@athenna/core/testing/BaseConsoleTest'

export default class ExampleTest extends BaseConsoleTest {
@Test()
public async 'test successful output'({ command }: Context) {
this.ignite 👈
}
}
```
20 changes: 15 additions & 5 deletions docs/testing/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ node artisan test

## Environment

When running tests, Athenna will automatically set the
[configuration environment](/docs/getting-started/configuration)
to `test`, meaning that the `.env.test` file will be used when
By default Athenna comes set with the
[configuration environment](/docs/getting-started/configuration)
as `test`, meaning that the `.env.test` file will be used when
running your tests.

You are free to define other testing environment value. To do
that you can use the `setAppEnv()` method of `Runner` class
that you can simply change the `setAppEnv()` method of `Runner` class
in your `Path.bootstrap('test.ts')` file:

```typescript
Expand All @@ -57,17 +57,27 @@ import { request } from '@athenna/http/testing/plugins'
import { command } from '@athenna/artisan/testing/plugins'

await Runner.setTsEnv()
.setAppEnv('testing') 👈
.addAssertPlugin()
.addPlugin(request())
.addPlugin(command())
.setAppEnv('testing') 👈
.addPath('tests/e2e/**/*.ts')
.addPath('tests/unit/**/*.ts')
.setCliArgs(process.argv.slice(2))
.setGlobalTimeout(5000)
.run()
```

:::tip

You can also use the `--env` flag to set the environment:

```shell
node artisan test --env testing
```

:::

## Writing tests

To create a new test case, use the `make:test` Artisan
Expand Down
Loading
Loading