Giter Site home page Giter Site logo

runner's Introduction

@japa/runner

An API first tests runner for Node.js

github-actions-image npm-image license-image typescript-image

Japa is an API first testing framework. It focuses only on testing Node.js (backend) applications, thus resulting in a fast, small, and a simple tests runner.

πŸ’ Please visit https://japa.dev for documentation



runner's People

Contributors

julien-r44 avatar thetutlage avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

runner's Issues

Adonis tests are failing when we setup application on different PC or location or after re-installing the dependencies.

Description

I don't know if this is a bug or not but all tests are failing when I set up the adonis application on a different location or PC or in case I delete the node_modules directory and re-install the npm dependencies. At the moment, I found two issues :

  1. route from the test context is getting undefined.
  2. loginAs function is not working.

Test 1

  test('Need email|mobile & password to login.', async ({ client, route }) => {
    const response = await client.post(route('api.login')).accept('json')

    response.assertStatus(422)

    response.assert?.containsSubset(response.body(), {
      errors: [{ field: 'email' }, { field: 'password' }],
    })
  })

Test 2

test('An authenticated user can see the list of categories too.', async ({ client, assert }) => {
    const categories = await CategoryFactory.createMany(5)

    const user = await UserFactory.create()

    const response = await client.get('/api/categories').loginAs(user).accept('json')

    response.assertStatus(200)

    response.assert?.equal(5, response.body()?.length)

    assert.containsSubset(response.body(), categories.map(({ id, type, name }) => ({ id, type, name })))
  })

These tests were passing when I set up the fresh AdonisJS application but failed after re-installing dependencies/relocating by repo clone. I have attached two screenshots of the test results.

Expected Behaviour

If route and loginAs functions were passing before push (Push to git repo) then it should be working when I clone the code and installl the dependencies in another location or PC.

Steps to Reproduce

  1. Install the fresh adonis application via commands.
  2. Write some functional tests (just like above I mentioned). Tests should utilize the functions route from the test context and loginAs in test suite body. Tests should be passing.
  3. Delete node_modules directory OR move application files to the new location without node_modules directory and install dependencies via yarn
  4. Run the test command node ace test and the above two test examples will fail.

Package version

v2.0.7

Error Message & Stack Trace

image

image

Relevant Information

Question: Flag to bail / fail early?

Package version

3.0.0-9

Describe the bug

Is there a flag to stop the runner and print the errors after the first test failure?

Reproduction repo

No response

Unknown file extension ".ts" for

Description

While trying to use esno with typescript I'm getting stuck on an error.

Package version

japa 0.14.1

Error Message & Stack Trace

❯ esno .\bin\test.ts

   Unknown file extension ".ts" for C:\Users\xo\code\omgimalexis\scratch-pad\tests\maths.spec.ts

   at async importFiles C:/Users/xo/code/omgimalexis\scratch-pad/node_modules/@japa/runner/build/index.js:241
    236|              if (isFileAllowed(file, runnerOptions.filters.files)) {
    237|                  await runnerOptions.importer(file);
    238|              }
    239|          }
    240|          else {
  > 241|              await runnerOptions.importer(file);
    242|          }
    243|      }
    244|  }
    245|  /**
    246|   * Run japa tests

Relevant Information

I needed to apply the fix from #2 first.

Open APIs to get the current test/group and file name from a plugin

Hey !

I started to take a quick look at writing a snapshot testing plugin for Japa.

I was quickly confronted with this problem. It seems to me that we have no API to retrieve the name of the test/group, as well as the name of the file currently executed.

I need this information to write a snapshot file next to the executed test file, and its content must include the name of the executed test.

I think we could have something quite similar to the Tracker (or use this class but maybe split the "report summary generation" aspect into another class).

What do you think about it? Do you have any better recommendations?

[Bug]: "Only file and data URLs are supported by the default ESM loader" when running in Windows environment.

Description

Hello guys. I have a project here in GitHub that is using ESM. Every commit to this project triggers a GitHub Actions CI pipeline that runs the Japa tests in Linux environment and then in Windows environment.

Package version

2.0.7

Error Message & Stack Trace

In Linux environment everything works well. But on Windows, I'm facing this error:

image

Relevant Information

Steps to reproduce

I think it is a little hard to reproduce this problem because it is happening only on Windows. But here is it:

  1. Clone my project at: https://github.com/AthennaIO/Template
  2. npm install
  3. npm run test (The error comes up)

Migrations should be run silently.

Description

Currently, the database migrate runner hook shows the output for migrate and rollback in terminal which is very annoying. I have to scroll a lot to find the test runs and their results. There should be option to omit these outputs or need to hide permanently.

tests/bootstrap.ts

/*
|--------------------------------------------------------------------------
| Runner hooks
|--------------------------------------------------------------------------
|
| Runner hooks are executed after booting the AdonisJS app and
| before the test files are imported.
|
| You can perform actions like starting the HTTP server or running migrations
| within the runner hooks
|
*/
export const runnerHooks: Required<Pick<Config, 'setup' | 'teardown'>> = {
  setup: [() => TestUtils.ace().loadCommands(), () => TestUtils.db().migrate()],
  teardown: [],
}

Missing type declaration for nested module import `@japa/runner/reporters`

Package version

3.0.5

Describe the bug

The docs mention importing reporters from @japa/runner/reporters, but this nested module import does not seem to have a type declaration. Using the import still works however.

Example config

import { configure, processCLIArgs, run } from '@japa/runner';
import { spec } from '@japa/runner/reporters';

processCLIArgs(process.argv.slice(2));

configure({
  files: ['src/test/**/*.spec.ts'],
  reporters: {
    activated: ['spec'],
    list: [spec()],
  },
});

(async () => {
  await run();
})();

Shows an intellisense error Cannot find module '@japa/runner/reporters' or its corresponding type declarations. ts(2307)

Reproduction repo

No response

'npm init japa' fails with '@japa/browser-client'

Package version

[email protected]

Describe the bug

When doing a npm init japa command (docs: https://www.npmjs.com/package/create-japa), if @japa/browser-client plugin is selected, the initialization fails with a playwright error:

npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: process.cwd()@0.0.0
npm ERR! Found: [email protected]
npm ERR! node_modules/playwright
npm ERR!   dev playwright@"1.43.0-alpha-1709823751000" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer playwright@"^1.38.1" from @japa/[email protected]
npm ERR! node_modules/@japa/browser-client
npm ERR!   dev @japa/browser-client@"2.0.0-4" from the root project

Reproduction repo

No response

Plugin-augmented properties (e.g. assert) not available in Deno

Package version

3.1.1

Describe the bug

In Node.js, given a plugin configuration such as:

configure({
  files: ['tests/**/*.test.ts'],
  plugins: [assert()],
});

The TestContext object is augmented with an "assert" property:

TestContext.getter('assert', () => new Assert(), true)

However, when running the test script using Deno, the test context which is passed to the test function does not have this property – see this failing test run.

When looking at the code, I see that @japa/assert uses import { TestContext } from '@japa/runner/core' while the code that's creating the test context uses import { TestContext as BaseTestContext } from '@japa/core'.

Somehow this works in Node.js but not in Deno – but why? I understand that Deno may not be a target runtime for Japa, but I came to Japa because Jest does not work in Deno (see this issue which discusses some of the problems).

Reproduction repo

https://github.com/malthe/japa-runner/tree/typing-issue

[META] endless loop when trying to create a feature request issue on github

Package version

N/A

Describe the bug

This isn't a bug with japa itself, but rather the repository issue configuration.

Steps to reproduce::

Actual Functionality:

  • You are brought to the exact same issue selection page in a new tab.

Expected Functionality

  • You are able to file a feature request issue

So basically its currently not possible to file a feature request issue with the current UI, you just end up back on the issue type selection page.

Reproduction repo

No response

Trying to upload non-existing file hangs test suite

Package version

2.2.1

Describe the bug

When trying to upload a file that doesn't exist, the test runner hangs and never prints a summary or exits the process. This used up all my GitHub action minutes whilst I slept last night :(

import { join } from "node:path";
import { test } from "@japa/runner";

const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

test.group("Service Provider Profile", async (group) => {
  // In my app I'm doing a database transaction
  // ------------------------------------------
  // group.each.setup(async () => {
  //   await Database.beginGlobalTransaction();
  //   return async () => await Database.rollbackGlobalTransaction();
  // });

  // but this is needed to trigger the hang
  // without this setup the hang does not occur
  // ------------------------------------------
  group.each.setup(async () => {
    await sleep(1);
    return async () => await sleep(1);
  });

  test("upload hangs", async ({ client }) => {
    await client
      .post(`/api/v1/upload`)
      .file("avatar", join(__dirname, "../does/not/exist/", "file.jpg"));
  });
});

There is a reproduction repo. Simply clone npm install and run node ace test.

Reproduction repo

https://github.com/evoactivity/upload-hang-reproduction

Bug with assertAgainstApiSpec on Adonisjs

Package version

2.2.1

Describe the bug

Hi,

I've a bug with using APIClient when i test a route API contains a slug /admin/clients/:id

image

On my OpenAPISchema i define also a route with slug like this

path:
    /admin/client/{id}:

or

path:
    /admin/client/:id:

But you can see on the screenshot, he don't find the route because he's search with the id not with the slug

Thank you

Reproduction repo

No response

Planning Japa version 3

Its been more than a year since we released Japa v2 (a rewrite). Now, we have collected some ideas and a plan to migrate to ESM, so it feels like the perfect moment for v3.

Note: Migrating from Japa v2 to v3 will be relatively simple, with the only exception of moving from CJS to ESM. If your apps are already in ESM, then migrating should be a few minutes task.

Note: Have a feature in mind? Feel free to comment in this issue, we will see if it can make its way to v3.

Moving to ESM

As Node.js ecosystem is moving to ESM, it is becoming harder to rely on dependencies that works with CommonJS. As a side-effect, sometimes we cannot get security patches, or get deprecation warnings.

Moving to ESM is really not a choice. We can delay it, but it has to happen one day.

We will rewrite the Japa packages in ESM, therefore, the host application (the one using Japa) has to use ESM as well in order to import Japa inside the codebase.

Feature requests

  • Support for registering multiple reporters and activating them with a config change or command line flag. This way, you have multiple reporters and switch between them based upon the current environment.

Issues to look into

Internals

We have to cleanup the internals of the @japa/runner package. Since, most of the hard work is done by @japa/core, I went lazy and dumped all the code of the runner package in one file.

But, I think, we should clean it up now and make it more streamlined.

Update: The codebase is a lot cleaner and well organized now. c57d344

Releases

Test runner breaks when error is thrown

Description

The test runner seems to break when an error is thrown within a function irrespective of the assertion, assert.throws, being used.

For example: I have a simple function which throws an error when the permission is not found in a stub file:

export const getPermission = function (name: string) {
  const permission = permissions.find((p) => p.name === name)
  if (!permission) {
    throw new RangeError(`Provided permission "${name}" is invalid`)
  }
  return permission.name
}```

And the following unit test:

```ts
  test('should throw error if the permission name if invalid', async ({ assert }) => {
    assert.throws(() => getPermission('Can List All Users'))
  })
  })```


## Package version
    "@japa/api-client": "^1.3.1",
    "@japa/assert": "^1.3.4",
    "@japa/preset-adonis": "^1.0.16",
    "@japa/run-failed-tests": "^1.0.7",
    "@japa/runner": "^2.0.8",
    "@japa/spec-reporter": "^1.1.12",

## Error Message & Stack Trace

```text
Provided role "Global Enterprise Manager" is invalid
  
   at getRole app/Services/AccessControlService.ts:15
    10|  }
    11|  
    12|  export const getRole = function (name: string) {
    13|    const role = roles.find((p) => p.name === name)
    14|    if (!role) {
  ❯ 15|      throw new RangeError(`Provided role "${name}" is invalid`)
    16|    }
    17|    return role.name
    18|  }
    19|  
    20|  export const PERMISSIONS = {

Relevant Information

Should setup group-hook inject stuff into test context

Description

I've tried injecting stuff into the test context and it worked. But this is not documented, is this a bad pattern?

test.group("foo endpoint", (group) => {
  group.each.setup(async (test) => {
    const drive = Drive.fake("gcs");

    // @ts-ignore
    test.context.drive = drive;

    return () => Drive.restoreAll();
  });

  test("mocked disk test", async ({ test: { context } }) => {
    // @ts-ignore
    console.log(context.drive); // πŸ‘ˆprints actually
  });
});

Alternative is getting the instance in the test scope but restoring everything at the teardown, I guess. But it feels weird to copy paste drive mocking setup in each test.

test.group("foo endpoint", (group) => {
  group.each.teardown(async (test) => {
    Drive.restoreAll();
  });

  test("mocked disk test", async ({ test: { context } }) => {
    const drive = Drive.fake("gcs");
	
	// send request here

	// assertions
	assert.equal(await drive.get('package.json'), JSON.stringify({}))

	// let the teardown hook do the cleanup
  });
});

Package version

v2.0.7

Consider adding snapshot `hint`

Package version

next

Describe the bug

This is feature request, not a bug report (for some reason Feature Request temple does not work).

I was looking for a lighter testing framework for a CLI tool. Japa looks like a good candidate, because of snapshots and FS wrapper. Most of the test I have are e2e tests. The CLI tool runs in a spawned process and I snapshot stderr / stdout. (Also in many cases fixture files have to be written and clean up.)

A single test checks both stderr and stdout in separate snapshots. I was wondering if it would be possible to add snapshot hint similar to what Jest has: https://jestjs.io/docs/next/expect#tomatchsnapshotpropertymatchers-hint

import { test } from "@japa/runner";

test("handles feature", async ({ assert }) => {
  const { exitCode, stderr, stdout } = await spawn(fixtureUrl, ["feature"]);

  assert.snapshot(normalizeOutput(stderr)).match("stderr"); //  <- hint could be used here
  assert.snapshot(normalizeOutput(stdout)).match({ hint: "stdout" }); //  <- might be even better to pass it as an option

  assert.equal(exitCode, 0);
});

Reproduction repo

No response

Add help commands to "processCliArgs"

Description

As a user of japa I would like to quickly look up the documentation for the CLI by using the standard -h and --help commands. This improves both the ergonomics and is less surprising to the user. I was surprised when I included the help flag and instead of spitting out the help text it ran all my tests.

Can't use project's root folder in runner config

Package version

4.0.0

Describe the bug

Hi,

When I try to use project's root folder to set up runner config, I'm getting the following error

   ReferenceError: describe is not defined


   ⁃ Object.<anonymous>
     node_modules/json-schema-traverse/spec/index.spec.js:6
   ⁃ async importFiles
     node_modules/@japa/runner/build/index.js:151

My bin/test.js file looks like

import { assert } from '@japa/assert'
import { pathToFileURL } from 'node:url'
import { apiClient } from '@japa/api-client'
import { specReporter } from '@japa/spec-reporter'
import { processCliArgs, configure, run } from '@japa/runner'

configure({
  ...processCliArgs(process.argv.slice(2)),
  ...{
    files: ['./**/*.spec.js'],
    plugins: [assert(), apiClient('http://localhost:3333')],
    reporters: [specReporter()],
    importer: (filePath) => import(pathToFileURL(filePath).href),
  },
})

run()

Reproduction repo

No response

Unable to run migrations in github workflow when automating test runner

Description

I am trying to automate the test runner in my github workflow and it will exit with an error on ace commands. Running the test runner locally works as expected.

Not sure if I should have posted this here or in the adonis repo itself.

Even if there is a decent example of setting up running tests with the db for a github workflow, that would be greatly appreciated.

Package version

^4.0.0

Error Message & Stack Trace

Error: Command failed with exit code 1: node ace migration:run
    at makeError (/home/runner/work/portal-api/portal-api/node_modules/execa/lib/error.js:60:11)
    at handlePromise (/home/runner/work/portal-api/portal-api/node_modules/execa/index.js:118:26)
    at processTicksAndRejections (internal/process/task_queues.js:[95](https://github.com/DirectLink-AI/portal-api/runs/5773496600?check_suite_focus=true#step:7:95):5)
    at runMigrations (/home/runner/work/portal-api/portal-api/japaFile.ts:32:3)
    at run (/home/runner/work/portal-api/portal-api/node_modules/japa/build/src/SlimRunner/index.js:107:9) {
  shortMessage: 'Command failed with exit code 1: node ace migration:run',
  command: 'node ace migration:run',
  escapedCommand: 'node ace "migration:run"',
  exitCode: 1,
  signal: undefined,
  signalDescription: undefined,
  stdout: undefined,
  stderr: undefined,
  failed: true,
  timedOut: false,
  isCanceled: false,
  killed: false
}

Relevant Information

Just to note, I have a .env.testing file for any necessary environment variables for my application

I have in my workflow already set up postgres, node, and installed the dependecies:

name: validate-pull-requests
on:
  pull_request:
    branches:
      - dev
      - staging
      - main
jobs:
  lint-test-build:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres
        env:
          POSTGRES_USER: root
          POSTGRES_PASSWORD: root
          POSTGRES_DB: test
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Setup Node
        uses: actions/setup-node@v2
        with:
          node-version: '14.19.0'

      - name: Install Dependecies
        run: npm install

      - name: Run Linter
        run: npm run lint

      - name: Run Tests
        run: npm run test

      - name: Run the build
        run: npm run build

and here is my japaFile in order to set up the test dbs and run the migrations:

import 'reflect-metadata'
import pgtools from 'pgtools'
import execa from 'execa'
import { join } from 'path'
import getPort from 'get-port'
import { configure } from 'japa'
import sourceMapSupport from 'source-map-support'

process.env.NODE_ENV = 'testing'
process.env.ADONIS_ACE_CWD = join(__dirname)
sourceMapSupport.install({ handleUncaughtExceptions: false })

const dbConfig = {
  user: 'root',
  password: 'root',
  port: 5432,
  host: 'localhost',
}

const handleDBCallback = (error, result) => {
  if (error) console.log(error.message)
  else console.log(result)
}

async function createTestDbs() {
  pgtools.createdb(dbConfig, 'test', handleDBCallback)
  pgtools.createdb(dbConfig, 'dl-test-1', handleDBCallback)
  pgtools.createdb(dbConfig, 'dl-test-2', handleDBCallback)
}

async function runMigrations() {
  await execa('node', ['ace', 'migration:run'], { stdio: 'inherit' })

  await execa('node', ['ace', 'migration:run', '-c', 'dl-test-1'], { stdio: 'inherit' })

  await execa('node', ['ace', 'migration:run', '-c', 'dl-test-2'], { stdio: 'inherit' })
}

async function rollbackMigrations() {
  await execa('node', ['ace', 'migration:rollback', '--batch=0'], { stdio: 'inherit' })

  await execa('node', ['ace', 'migration:rollback', '-c', 'dl-test-1', '--batch=0'], {
    stdio: 'inherit',
  })

  await execa('node', ['ace', 'migration:rollback', '-c', 'dl-test-2', '--batch=0'], {
    stdio: 'inherit',
  })
}

async function startHttpServer() {
  const { Ignitor } = await import('@adonisjs/core/build/src/Ignitor')
  process.env.PORT = String(await getPort())
  await new Ignitor(__dirname).httpServer().start()
}

function getTestFiles() {
  let userDefined = process.argv.slice(2)[0]
  if (!userDefined) {
    return 'test/**/*.spec.ts'
  }

  return `${userDefined.replace(/\.ts$|\.js$/, '')}.ts`
}

/**
 * Configure test runner
 */
configure({
  files: getTestFiles(),
  before: [createTestDbs, runMigrations, startHttpServer],
  after: [rollbackMigrations],
})

group.each.setup don't seem to be called from configureSuite

Description

First of all, I am not entirely sure if this is a bug, but I'll describe what is happening:
I recently created a project with Adonis.js, created some models and wrote some tests. I followed this instructions to wrap each test on a DB transaction.

I noticed that most of the time, the tests passed, but often times some would fail with duplicated key errors when trying to insert a record in the DB. I double, triple, quadruple checked the codes, and they seemed to be ok, so I went digging deeper.

This is what the bootstra.ts file looked like initially:

import { expect } from '@japa/expect'
import type { Config } from '@japa/runner'
import TestUtils from '@ioc:Adonis/Core/TestUtils'
import Database from '@ioc:Adonis/Lucid/Database'
import { assert, runFailedTests, specReporter, apiClient } from '@japa/preset-adonis'

export const plugins: Config['plugins'] = [assert(), runFailedTests(), apiClient(), expect()]

export const reporters: Config['reporters'] = [specReporter()]

export const runnerHooks: Required<Pick<Config, 'setup' | 'teardown'>> = {
  setup: [() => TestUtils.ace().loadCommands(), () => TestUtils.db().migrate()],
  teardown: [],
}

export const configureSuite: Config['configureSuite'] = (suite) => {
  suite.setup(() => TestUtils.httpServer().start())
  suite.onGroup((group) => {
    group.each.setup(async () => {
      await Database.beginGlobalTransaction()
      return () => Database.rollbackGlobalTransaction()
    })
  })
}

And the I change the configureSuite const with a log and a throw:

export const configureSuite: Config['configureSuite'] = (suite) => {
  suite.setup(() => TestUtils.httpServer().start())
  suite.onGroup((group) => {
    console.log(group.title)
    group.each.setup(async () => {
      throw new Error('This should crash and fail the tests (I suppose)')
      await Database.beginGlobalTransaction()
      return () => Database.rollbackGlobalTransaction()
    })
  })
}

As expected, the console.log call did print all the test group titles. However, the throw call did not seem to have any effect at all. The tests continued to be ran, most of them succeed, others fail like said before.

Then I went further and wrote two simple test cases:

import { test } from '@japa/runner'

import Message from 'App/Models/Message'
import MessageService from 'App/Services/Message'

import { MessageFactory } from 'Database/factories'


test.group('some group', () => {
  test('first test that usually passes', async ({ expect }) => {
    const message = await MessageFactory.merge({ someUniqueValue: 123 }).create()

    await new MessageService().processSentMessage(message)

    expect(message.sentAt).not.toBeNull()
  })

  test('second test that usually fails', async ({ expect }) => {
    const oldMessages = await Message.all()

    // I expected this to always log 'THERE ARE 0 MESSAGES'
    // but it often logs 'THERE ARE 1 MESSAGE', I assume remains from the previous test
    console.log(`THERE ARE ${oldMessages.length} MESSAGES: ${oldMessages.map(m => m.id)}`)

    const message = await MessageFactory.merge({ someUniqueValue: 123 }).create()

    await new MessageService().processDeliveredMessage(message)

    expect(message.deliveredAt).not.toBeNull()
  })
})

And just like written in the comment, very often the second test starts with non-empty table of Messages.

Package version

    "@japa/expect": "^1.1.4",
    "@japa/preset-adonis": "^1.0.15",
    "@japa/runner": "^2.0.7",

Error Message & Stack Trace

βœ– second test that usually fails

   insert into "messages" ("created_at", "some_unique_value", "updated_at") values ($1, $2, $3) returning "id" - duplicate key value violates unique constraint "messages_some_unique_value_unique"

Relevant Information

If this is not a bug from Japa itself, the only hypothesis I could come up with is something wrong the the async/await calls, but I'm not sure.

I only tested with groups.each.setup but I believe the issue occurs with teardown, timeout or any other method from group.each.

I hope I included enough info to help debug this, but let me know if there's anything else I can provide.

Add `--reporters` argument

So let's imagine that the user defines several reporters :

configure({
  reporters: [specReporter(), dotReporter()]
})

In this case, we would like to have the output of a single reporter. But to also be able to choose the output of another reporter in a different context. For example, the SpecReporter would be for local dev, and the DotReporter for the CI.


Update ReporterContract

The first thing to do would be to define names for the reporters so that they can be selected later via a --reporter argument. My suggestion is this:

// Instead of 
export type ReporterContract = (runner: Runner<any>, emitter: Emitter) => void | Promise<void>;

// The reporter factory would return an object like this. Name and manager
export type ReporterContract = {
   name: string // Would be 'dot', or 'spec', for the above example
   handler: (runner: Runner<any>, emitter: Emitter) => void | Promise<void>
}

However, this would consist of a breaking change. Which is pretty annoying for a small feature like this. My other suggestion, so that it does not cause a breaking change :

  • Modify the ReporterContract as follows :
type ReporterHandler = (runner: Runner<any>, emitter: Emitter) => void | Promise<void>
type ReporterContract = 
 | { name: string; handler: ReporterHandler } 
 | ReporterHandler

And in case, just the handler is defined, without any name, maybe we could just assign a random one. When a user tries to use only his reporter via the --reporters argument, and it is not found, we could display an error like "Reporter not found. Make sure you define a name for it".


Select a reporter

To activate reporters, what I suggest :

  • Just a flag --reporters which accepts a list of names of reporters. node bin/test.ts --reporters=dot,json,spec or node bin/test.ts --reporters=dot

Now the thing that's a bit boring. If I go back to the configuration that I put at the top of the issue. If I run my tests with node bin/test.ts without specifying any reporter, then both (dot and spec) will be enabled.
So always having to specify a reporter could be a bit of a pain.

What I propose here is to add an enabled property in the contract of each reporter :

// The reporter factory would return an object like this. Name and manager
export type ReporterContract = 
 | { 
     name: string; 
     handler: ReporterHandler 
     enabled: boolean
   } 
 | ReporterHandler

By default, spec and dot would be set to enabled = false. Passing the name of the reporter via the flag would enable it. And if ever, when notifying the reporters in the runner, we realize that none of the reporters are enabled (which means that no --reporters argument has been passed) then we'd default to enabling the spec reporter.

I'm not really convinced by this solution, but it's the only one I could see


In closing, there's a question I've been asking myself:

Why allow multiple reporters? Will the user really need to run several reporters at the same time?
If this is not the case, what I would suggest is maybe something like this :

// Specifiy one reporter
configure({
  reporter: 'dot'
})

// Specify custom reporter
configure({
  reporter: './path/to/reporter.ts' // or '@org/reporter'
})

And then we would import, directly from the runner, the reporter. Exactly like pino does with the transporters for example: https://github.com/Julien-R44/pino-loki#as-module

( For example, when you want to use pino-pretty, it tries to import it on its own, and if it doesn't find it, we get a nice error that invites us to install it. )

Let me know what you think about it !

Need HTML Test report

Description

As of now we have only terminal reporting. It will be good if we implement HTML test report.

Package version

2.0.8

Question: Including typings for plugins (i.e. assert)

Package version

3.1.1

Describe the bug

Given a test script like below, how should one best get the typings included for TestContext properties assert and expect which are already declared in @japa/assert and @japa/expect.

import { configure, processCLIArgs, run } from '@japa/runner';
import { assert } from '@japa/assert'
import { expect } from '@japa/expect';

processCLIArgs(process.argv.splice(2));

configure({
  files: ['tests/**/*.spec.ts'],
  plugins: [assert(), expect()],
});

run();

That is, how does one remove the red squiggly line under assert in the following test file:

import { test } from '@japa/runner';
import type { TestContext } from '@japa/core';

function sum(a: number, b: number) {
  return a + b
}

test('add two numbers', ({ assert }: TestContext) => {
  assert.equal(sum(2, 2), 4)
})

Reproduction repo

No response

Config `importer` function returns wrong path when using ESM loader

Package version

2.2.2

Describe the bug

Node.js versions 16.17.0 & 18.12.1

Hello!

I have an ESM project and I tried to integrate Japa to run tests. However, when I run this command
node --loader=ts-node/esm bin/test.ts I get the following error:

Only URLs with a scheme in: file, data are supported by the default ESM loader. On Windows, absolute paths must be valid file:// URLs. Received protocol 'c:'


     1  defer
       node_modules/.pnpm/[email protected]_2ddbbb1508daf8c6199f587657236c9e/node_modules/ts-node/src/esm.ts:159

     2  entrypointFallback
       node_modules/.pnpm/[email protected]_2ddbbb1508daf8c6199f587657236c9e/node_modules/ts-node/src/esm.ts:168

     3  anonymous
       node_modules/.pnpm/[email protected]_2ddbbb1508daf8c6199f587657236c9e/node_modules/ts-node/src/esm.ts:202

       node_modules/.pnpm/[email protected]_2ddbbb1508daf8c6199f587657236c9e/node_modules/ts-node/src/esm.ts:409

     5  resolve
       node_modules/.pnpm/[email protected]_2ddbbb1508daf8c6199f587657236c9e/node_modules/ts-node/src/esm.ts:197

Same thing with tsx.

This is my tsconfig.json file:

{
  "compilerOptions": {
    "target": "ESNext",
    "lib": [
      "ESNext",
      "DOM"
    ],
    "module": "ESNext",
    "moduleResolution": "Node",
    "baseUrl": ".",
    "typeRoots": [
      "src/types"
    ],
    "outDir": "./dist",
    "isolatedModules": false,
    "esModuleInterop": true,
    "skipLibCheck": true
  },
  "exclude": ["node_modules", "dist"],
  "ts-node": {
    "esm": true,
    "transpileOnly": true
  }
}

I have a simple test file:

import { test } from "@japa/runner";

import parsePolicy from "../src/parse_policy.js";

const policy = {
  "@context": "http://www.w3.org/ns/odrl.jsonld",
  "@type": "Set",
  uid: "http://example.com/policy:1010",
  permission: [
    {
      target: "http://example.com/asset:9898.movie",
      action: "use",
    },
  ],
};

test.group("Policy parser", () => {
  test("should parse ODRL policy", async ({ assert }) => {
    const parsedPolicy = await parsePolicy(JSON.stringify(policy));

    assert.lengthOf(parsedPolicy.permissions, 1);
  });
});

Thank you!

Reproduction repo

No response

Allow failing slowly in a test case

Description

As soon as an assertion fails, test case also fails. This increases the feedback loop for the user, instead of finding out all failing assertions in one run you have to iterate over each assertion line to see the problem as whole on a test case.

Example:

test('should return 2 failures', async ({ assert }) => {
	  assert.ok(null)
	  assert.ok(0)
})

Expected: 2 assertions failed line 123 and 124.
Actual: Assertion Error: expected null to be truthy (A pretty print pointing at line 123)

Package version

"@japa/preset-adonis": "^1.0.15",
"@japa/runner": "^2.0.7",

Relevant Information

This is the default behavior at Rails.

Test runner breaks when `group` handler is `async`

Description

Japa seems not to support async handler current and breaks with the following unexpected behaviours:

  1. All test running within the group with the async handler fails without any specific error,
  2. Pinning all tests within the group with group.tap((test) => test.pin()) results in all tests running (not just the tests within the pinned group).
  3. Pinning only one tests within a group with the async handler runs few random tests with the pinned tests still failing.

Package version

    "@japa/api-client": "^1.2.0",
    "@japa/assert": "^1.3.4",
    "@japa/preset-adonis": "^1.0.15",
    "@japa/run-failed-tests": "^1.0.7",
    "@japa/runner": "^2.0.7",

Error Message & Stack Trace

As seen below, the failed test was the only pinned test within a group with async handler but few other random tests ran while the pinned test still failed.

unit / Pagination Service (tests/unit/pagination_service.spec.ts)
  βœ” should return same pagination values if they are valid (1ms)
  βœ” should use `1` as `page` value if not provided (0ms)
  βœ” should use `20` as `per_page` value if not provided (0ms)
  βœ” should use `50` as `per_page` value if provided value is greater `50` (0ms)
{"level":30,"time":1653300409042,"pid":27492,"hostname":"Ndianabasi-Mac.lan","name":"backend-v1","msg":"started server on 0.0.0.0:4444"}

functional / Authentication (tests/functional/auth.spec.ts)
  βœ” User login should be successful (130ms)

tests/functional/workspace_users/update_users.spec.ts
  βœ– A superadmin can create and associate a user in any workspace (108ms)

Relevant Information

Example of what I am trying to achieve with async group handler is generating a fake file only once for the all tests within a group:

test.group('Workspace Users | create', async (group) => {
  group.each.setup(async () => {
    await Database.beginGlobalTransaction()
    return () => Database.rollbackGlobalTransaction()
  })

  const role = () => faker.helpers.arrayElement(['designer', 'admin', 'manager'])
  const fakeAvatar = await file.generatePng('1mb')

  test('A superadmin can create and associate a user in any workspace', async ({
    assert,
    client: apiClient,
    route,
  }) => {

...

    const response = await apiClient
      .post(route('WorkspaceUsersController.store', [workspace.id]))
      .field('full_name', newUser.fullName)
      .field('email', newUser.email)
      .field('role', role())
      .file('avatar', fakeAvatar.contents, { filename: fakeAvatar.name })
      .loginAs(superadmin)

...

  })
})

Japa watch mode?

Description

Does Japa have a watch mode function? I couldn't find anything about this in the documentation.

Package version

2.0.5

Awesome Japa

I am collecting links to articles, packages, videos, etc. related to Japa. If you have created anything for Japa, then comment on this issue. I will occasionally pick links from the comments and update the main issue

Property 'expect' does not exist on type TextContext

Package version

2.2.2

Describe the bug

In VSCode the expect variable on TextContext is not defined as far as TS is concerned. Test works as expected in runtime.

It seems like when I have the bin/test.ts open in a split pane next to my spec file it can resolve the type OK, but if I just have the spec file open it shows the error and obviously no autocompletion or anything.

Might be a VSCode specific issue, but I'd assume it should be able to pick up the correct typing since I haven't seen any special setup instructions. Even when trying to add it to something like japaTypes.ts doesn't fix the issue, but also expect does exist on TextContext in that declaration.

image

image

Reproduction repo

https://github.com/derekr/japa-expect-ts-error

Typescript non-relative path class imports

Description

I'm trying to setup Japa to run typescript tests with ts-node into an existing Adonis v5.6.2 project. Setting up a basic test and importing classes from npm modules works fine.

In my test I'm trying to test password hashing like the old Japa docs for Adonis. I would assume that the tsconfig.json files and presets will pull in the correct import paths, but that doesn't seem to be the case.

Package version

2.0.6

Error Message & Stack Trace

test.spec.ts

import { test } from '@japa/runner'
import User from 'App/Models/User';

test('ensure user password gets hashed during save', async ({assert}) => {
    const user = new User()
    user.email = "[email protected]"
    user.password = "secret"
    await user.save()

    assert.notEqual(user.password, 'secret')
})
❯ npm run test

> [project]@1.0.0 test
> node -r ts-node/register/transpile-only bin/test.ts


   Cannot find module 'App/Models/User'
Require stack:
- /Users/[user]/[project]/tests/test.spec.ts
- /Users/[user]/[project]/bin/test.ts
  
   at Function.Module._resolveFilename internal/modules/cjs/loader.js:902

Updating the import User to a relative import works for importing the User model class, but fails at importing '@IOC:Adonis/Core/Hash'

import { test } from '@japa/runner'
import User from '../app/Models/User';

test('ensure user password gets hashed during save', async ({assert}) => {
    const user = new User()
    user.email = "[email protected]"
    user.password = "secret"
    await user.save()

    assert.notEqual(user.password, 'secret')
})
❯ npm run test

> [project]@1.0.0 test
> node -r ts-node/register/transpile-only bin/test.ts


   Cannot find module '@ioc:Adonis/Core/Hash'
Require stack:
- /Users/[user]/[project]/app/Models/User.ts
- /Users/[user]/[project]/tests/test.spec.ts
- /Users/[user]/[project]/bin/test.ts
  
   at Function.Module._resolveFilename internal/modules/cjs/loader.js:902

"with" is executed before "setup" when running a test

Description

This is not a bug, i believe it is a more a discussion than a bug.

When running an functional test in japa my "with" function is executed before my test setup function.

Let me illustrate my use case:

i have the following test configuration:

import 'reflect-metadata'
import sourceMapSupport from 'source-map-support'
import execa from 'execa'
import { assert } from '@japa/assert'
import { specReporter } from '@japa/spec-reporter'
import { processCliArgs, configure, run } from '@japa/runner'
import { join } from 'path'
import type { HttpServer } from '@adonisjs/core/build/src/Ignitor/HttpServer'
import { Ignitor } from '@adonisjs/core/build/src/Ignitor'

sourceMapSupport.install({ handleUncaughtExceptions: false })

async function setupServer() {
  let server: HttpServer;
  try {
    server = new Ignitor(join(__dirname, '..')).httpServer()
    await server.start()
  } catch (error) {
    console.log("Erro ao subir o servidor de testes", error)
  }
  return async () => await server.close()
}

async function initTestBaseState() {
  const Database = (await import('@ioc:Adonis/Lucid/Database')).default;
  const { initCacheBaseState, resetCache } = (await import('Database/samples/SamplesUtils'));
  try {
    await execa.node('ace', ['migration:fresh', '--seed'], { stdio: 'inherit' });
    initCacheBaseState();
    await Database.beginGlobalTransaction()
  } catch (error) {
    console.log("Erro ao rodar migration:fresh", error)
  }
  return async () => {
    await Database.commitGlobalTransaction()
    resetCache();
  }
}

async function restoreTestBaseState() {
  const Database = (await import('@ioc:Adonis/Lucid/Database')).default;
  const { restoreCacheBaseState } = (await import('Database/samples/SamplesUtils'));
  await Database.rollbackGlobalTransaction()
  restoreCacheBaseState();
  await Database.beginGlobalTransaction()
}

configure({
  ...processCliArgs(process.argv.slice(2)),
  ...{
    suites: [
      {
        name: 'unit',
        files: ['japa/unit/**/*.fixture.ts'],
      },
      {
        name: 'acceptance',
        files: ['japa/acceptance/**/*.fixture.ts'],
        configure: (suite) => {
          suite.setup(initTestBaseState)
          suite.onTest(test => test.setup(restoreTestBaseState))
        }
      }
    ],
    setup: [setupServer],
    plugins: [assert()],
    reporters: [specReporter()],
    importer: (filePath) => import(filePath)
  },
})
run()

The order here -> it runs my setupServer function -> it runs my configureSuite function where i set the setup function of my funcional suite with Γ¬nitTestBaseState, right here i delete, migrate and seed my database and begin a global transaction that is going to be rolled back after each functional test -> after that i set the setup function of each test to rollback to the initial state of the migration

The problem is that my with functions contains data that's inserted on the database. If the with is executed before, i lose the data on the rollback of the setup function.

Do you belive that is a good idea to run setup before with ?

Package version

2.0.3

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.