@tapjs/core
Advanced tools
Comparing version 0.0.0-15 to 0.0.0-16
@@ -8,3 +8,3 @@ /** | ||
import { CallSiteLike, CallSiteLikeJSON } from '@tapjs/stack'; | ||
export * from './tap-file.js'; | ||
export * from '#tap-dir'; | ||
export * from './base.js'; | ||
@@ -21,3 +21,3 @@ export * from './counts.js'; | ||
export * from './stdin.js'; | ||
export * from './tap-dir.js'; | ||
export * from './tap-file.js'; | ||
export * from './test-base.js'; | ||
@@ -64,3 +64,2 @@ export * from './test-point.js'; | ||
error?: any; | ||
expectFail?: boolean; | ||
diagnostic?: boolean; | ||
@@ -67,0 +66,0 @@ tapChildBuffer?: string; |
@@ -24,3 +24,3 @@ "use strict"; | ||
exports.tap = void 0; | ||
__exportStar(require("./tap-file.js"), exports); | ||
__exportStar(require("#tap-dir"), exports); | ||
__exportStar(require("./base.js"), exports); | ||
@@ -37,3 +37,3 @@ __exportStar(require("./counts.js"), exports); | ||
__exportStar(require("./stdin.js"), exports); | ||
__exportStar(require("./tap-dir.js"), exports); | ||
__exportStar(require("./tap-file.js"), exports); | ||
__exportStar(require("./test-base.js"), exports); | ||
@@ -40,0 +40,0 @@ __exportStar(require("./test-point.js"), exports); |
{ | ||
"type": "commonjs" | ||
"type": "commonjs", | ||
"imports": { | ||
"#tap-dir": "./tap-dir-cjs.js" | ||
} | ||
} |
@@ -12,3 +12,4 @@ /// <reference types="node" resolution-mode="require"/> | ||
/** | ||
* Options that may be provided to the {@link @tapjs/core!stdin.TapFile} class | ||
* Options that may be provided to the {@link @tapjs/core!tap-file.TapFile} | ||
* class | ||
*/ | ||
@@ -15,0 +16,0 @@ export interface TapFileOpts extends BaseOpts { |
@@ -34,3 +34,2 @@ "use strict"; | ||
let autoend = false; | ||
let exitSignal = undefined; | ||
/** | ||
@@ -180,9 +179,2 @@ * This is a singleton subclass of the {@link @tapjs/test!index.Test} base | ||
if (registered && proc_js_1.proc && !results.ok) { | ||
// very finicky timing-specific behavior | ||
/* c8 ignore start */ | ||
if (exitSignal && proc_js_1.proc.kill && proc_js_1.proc.pid) { | ||
proc_js_1.proc.kill(proc_js_1.proc.pid, exitSignal); | ||
setTimeout(() => { }, 200); | ||
} | ||
/* c8 ignore stop */ | ||
this.debug('TAP results not ok, setting exitCode', results); | ||
@@ -189,0 +181,0 @@ proc_js_1.proc.exitCode = 1; |
@@ -386,5 +386,2 @@ "use strict"; | ||
} | ||
if (extra.expectFail) { | ||
ok = !ok; | ||
} | ||
if (extra.at === null) { | ||
@@ -391,0 +388,0 @@ delete extra.at; |
@@ -24,7 +24,2 @@ /// <reference types="node" resolution-mode="require"/> | ||
/** | ||
* Set internally to the numeric thread identifier once the worker is | ||
* instantiated. | ||
*/ | ||
threadId?: number; | ||
/** | ||
* Environment variables that are set in the worker thread | ||
@@ -40,2 +35,9 @@ */ | ||
eval?: boolean; | ||
/** | ||
* Set internally to the numeric thread identifier once the worker is | ||
* instantiated. | ||
* | ||
* @internal | ||
*/ | ||
threadId?: number; | ||
} | ||
@@ -42,0 +44,0 @@ /** |
@@ -8,3 +8,3 @@ /** | ||
import { CallSiteLike, CallSiteLikeJSON } from '@tapjs/stack'; | ||
export * from './tap-file.js'; | ||
export * from '#tap-dir'; | ||
export * from './base.js'; | ||
@@ -21,3 +21,3 @@ export * from './counts.js'; | ||
export * from './stdin.js'; | ||
export * from './tap-dir.js'; | ||
export * from './tap-file.js'; | ||
export * from './test-base.js'; | ||
@@ -64,3 +64,2 @@ export * from './test-point.js'; | ||
error?: any; | ||
expectFail?: boolean; | ||
diagnostic?: boolean; | ||
@@ -67,0 +66,0 @@ tapChildBuffer?: string; |
@@ -7,3 +7,3 @@ /** | ||
*/ | ||
export * from './tap-file.js'; | ||
export * from '#tap-dir'; | ||
export * from './base.js'; | ||
@@ -20,3 +20,3 @@ export * from './counts.js'; | ||
export * from './stdin.js'; | ||
export * from './tap-dir.js'; | ||
export * from './tap-file.js'; | ||
export * from './test-base.js'; | ||
@@ -23,0 +23,0 @@ export * from './test-point.js'; |
{ | ||
"type": "module" | ||
"type": "module", | ||
"imports": { | ||
"#tap-dir": "./tap-dir.js" | ||
} | ||
} |
@@ -12,3 +12,4 @@ /// <reference types="node" resolution-mode="require"/> | ||
/** | ||
* Options that may be provided to the {@link @tapjs/core!stdin.TapFile} class | ||
* Options that may be provided to the {@link @tapjs/core!tap-file.TapFile} | ||
* class | ||
*/ | ||
@@ -15,0 +16,0 @@ export interface TapFileOpts extends BaseOpts { |
@@ -31,3 +31,2 @@ /** | ||
let autoend = false; | ||
let exitSignal = undefined; | ||
/** | ||
@@ -177,9 +176,2 @@ * This is a singleton subclass of the {@link @tapjs/test!index.Test} base | ||
if (registered && proc && !results.ok) { | ||
// very finicky timing-specific behavior | ||
/* c8 ignore start */ | ||
if (exitSignal && proc.kill && proc.pid) { | ||
proc.kill(proc.pid, exitSignal); | ||
setTimeout(() => { }, 200); | ||
} | ||
/* c8 ignore stop */ | ||
this.debug('TAP results not ok, setting exitCode', results); | ||
@@ -186,0 +178,0 @@ proc.exitCode = 1; |
@@ -357,5 +357,2 @@ import * as stack from '@tapjs/stack'; | ||
} | ||
if (extra.expectFail) { | ||
ok = !ok; | ||
} | ||
if (extra.at === null) { | ||
@@ -362,0 +359,0 @@ delete extra.at; |
@@ -24,7 +24,2 @@ /// <reference types="node" resolution-mode="require"/> | ||
/** | ||
* Set internally to the numeric thread identifier once the worker is | ||
* instantiated. | ||
*/ | ||
threadId?: number; | ||
/** | ||
* Environment variables that are set in the worker thread | ||
@@ -40,2 +35,9 @@ */ | ||
eval?: boolean; | ||
/** | ||
* Set internally to the numeric thread identifier once the worker is | ||
* instantiated. | ||
* | ||
* @internal | ||
*/ | ||
threadId?: number; | ||
} | ||
@@ -42,0 +44,0 @@ /** |
{ | ||
"name": "@tapjs/core", | ||
"version": "0.0.0-15", | ||
"version": "0.0.0-16", | ||
"description": "pluggable core of node-tap", | ||
@@ -33,2 +33,14 @@ "author": "Isaac Z. Schlueter <i@izs.me> (https://blog.izs.me)", | ||
}, | ||
"imports": { | ||
"#tap-dir": { | ||
"import": { | ||
"types": "./dist/mjs/tap-dir.d.ts", | ||
"default": "./dist/mjs/tap-dir.js" | ||
}, | ||
"require": { | ||
"types": "./dist/cjs/tap-dir-cjs.d.ts", | ||
"default": "./dist/cjs/tap-dir-cjs.js" | ||
} | ||
} | ||
}, | ||
"files": [ | ||
@@ -51,4 +63,4 @@ "dist" | ||
"@tapjs/processinfo": "^2.5.6", | ||
"@tapjs/stack": "0.0.0-4", | ||
"@tapjs/test": "0.0.0-15", | ||
"@tapjs/stack": "0.0.0-5", | ||
"@tapjs/test": "0.0.0-16", | ||
"async-hook-domain": "^4.0.1", | ||
@@ -60,3 +72,3 @@ "is-actual-promise": "^1.0.0", | ||
"tap-parser": "15.0.0-2", | ||
"tcompare": "6.0.1-3", | ||
"tcompare": "6.0.1-4", | ||
"trivial-deferred": "^2.0.0" | ||
@@ -68,3 +80,6 @@ }, | ||
"url": "git+https://github.com/tapjs/tapjs.git" | ||
}, | ||
"engines": { | ||
"node": ">=16" | ||
} | ||
} |
222
README.md
@@ -5,196 +5,92 @@ # `@tapjs/core` | ||
The `TestBase` class has the basic flow-control and child-test | ||
aspects of a tap `Test` object, but only the `t.pass()` and | ||
`t.fail()` assertions. | ||
The `TestBase` class has the basic flow-control aspects of a tap | ||
`Test` object, but only the `t.pass()` and `t.fail()` assertions. | ||
All other assertions and features are added via plugins. | ||
## Writing Plugins | ||
Full documentation available in [the | ||
typedocs](https://tapjs.github.io/tapjs/modules/_tapjs_core.html). | ||
Tap plugins are a function that takes a `Test` object and an | ||
`options` object, and returns an object that is used as the | ||
extension. | ||
## Class `Base` | ||
For example, to add a `isString` method to all tests, you could | ||
define a plugin like this: | ||
This is the base class of all sorts of test objects. It inherits | ||
from [minipass](https://isaacs.github.io/minipass/). | ||
```ts | ||
import { TestBase, TapPlugin, AssertionOpts } from '@tapjs/core' | ||
export const plugin: TapPlugin = t => { | ||
return { | ||
isString: ( | ||
s: any, | ||
msg: string = 'expect string', | ||
extra: AssertionOpts = {} | ||
) => { | ||
// note: 'this' here is the plugin object | ||
if (typeof s === 'string') { | ||
return t.pass(msg) | ||
} else { | ||
return t.fail(msg, { | ||
...extra, | ||
expect: 'string', | ||
actual: typeof s, | ||
}) | ||
} | ||
} | ||
} | ||
``` | ||
## Class `TestBase` | ||
The object returned by a plugin can be any sort of thing. If you | ||
want to use a class with private properties, that's totally fine | ||
as well. Whatever type is expected as the second argument will | ||
be combined with the built-in `TestBaseOpts` interface, and | ||
required when tests are instantiated. | ||
This provides the core flow control and `TAP` generation | ||
facilities. The `Test` class inherits from this. | ||
```ts | ||
import { TestBase, TapPlugin, AssertionOpts } from '@tapjs/core' | ||
import { cleanup, render } from '@testing-library/react' | ||
import { ReactElement } from 'react' | ||
import { RenderResult } from '@testing-library/react' | ||
import userEvent from '@testing-library/user-event' | ||
class ReactTest { | ||
#result: RenderResult | ||
constructor(node: ReactElement) { | ||
this.#result = render(node) | ||
} | ||
findByText(text: string) { | ||
return this.#result.findByText(text) | ||
} | ||
// add other helpful methods here... | ||
} | ||
export const plugin: TapPlugin = (t, { node: ReactElement }) => { | ||
return new ReactTest(node) | ||
} | ||
``` | ||
## Class `Spawn` | ||
When loaded, this plugin would make it so that every test must | ||
supply a `{ node: ReactElement }` option, and would have a | ||
`t.findByText()` method. | ||
A child test class representing a child process that emits `TAP` | ||
on its standard output. | ||
## Loading Plugins | ||
## Class `Worker` | ||
The easiest way to load plugins is by running: | ||
A child test class representing a worker thread that emits `TAP` | ||
on its standard output. | ||
``` | ||
tap plugin add <package or local module> | ||
``` | ||
## Class `Stdin` | ||
This will also regenerate the Test class, so types are kept in | ||
sync. | ||
A child test class representing `TAP` parsed from standard input. | ||
Remove plugins with `tap plugin remove <plugin>`. | ||
## Class `TapFile` | ||
### Specifying Plugins Manually | ||
A child test class representing a file containing `TAP` data. | ||
Plugins are specified in the `plugins` array of the root tap | ||
config. That is, either `.taprc` in the project directory, or | ||
the `"tap"` stanza in the `package.json` file. | ||
## Class `Counts` | ||
Whenever the `plugins` option is changed, you must run `tap | ||
generate` to generate the `Test` class properly. This is done | ||
automatically on demand when running `tap` or `tap run | ||
[...files]`, but its often a good idea to do so before writing | ||
tests so that editor hinting is accurate. | ||
An object used to count pass, fail, todo, skip, total, | ||
and completed tests. | ||
## Built-In plugins | ||
## Class `Lists` | ||
Out of the box, tap comes with the following plugins loaded: | ||
An object containing lists of test results. | ||
- `@tapjs/core/plugin/before-each` Adds `t.beforeEach(fn)` | ||
- `@tapjs/core/plugin/after-each` Adds `t.afterEach(fn)` | ||
- `@tapjs/core/plugin/stdin` Adds `t.stdin()` | ||
- `@tapjs/core/plugin/spawn` Adds `t.spawn()` | ||
- `@tapjs/asserts` All other assertions, like `t.match()`, | ||
`t.type()`, `t.has()`, and so on. | ||
- `@tapjs/snapshot` Providing the `t.matchSnapshot()` method. | ||
- `@tapjs/fixture` Providing the `t.testdir()` method. | ||
- `@tapjs/mock` Providing the `t.mock()` method. | ||
## Class `TestPoint` | ||
To _prevent_ loading any of these plugins, you can include them | ||
in the `plugins` config, prefixed with a `!`. For example, if | ||
you wanted to replace `t.mock()` with a different mocking plugin, | ||
you could do this: | ||
An object representing a single `ok`/`not ok` test point. | ||
```json | ||
{ | ||
"tap": { | ||
"plugins": ["!@tapjs/mock", "my-mock-plugin"] | ||
} | ||
} | ||
``` | ||
## Class `Minimal` | ||
## Plugin Collisions | ||
A very minimal Test class with no plugins, which can be used in | ||
tap internal tests. | ||
The _first_ plugin in a list that provides a given method or | ||
property will be the one that "wins", as far as the object | ||
presented in test code is concerned. | ||
It is essentially just the TestBase class, but automatically | ||
starting in the constructor, and with a .test() method so that it | ||
can be used somewhat like a "normal" Test instance. | ||
However, _within_ a given plugin, it only sees itself and the | ||
`TestBase` object it's been given. For example, if returning an | ||
object constructed from a class defined in the plugin, `this` | ||
will refer to that object, always. | ||
The reason that this method does not live on TestBase itself is | ||
that it would make it more awkward to define on the Test class, | ||
with all its plugins and extensions. | ||
```js | ||
// first-plugin | ||
export const plugin = (t: TestBase) => { | ||
return { | ||
// this is the first plugin to register this value | ||
// so this is what shows up on the Test object | ||
myVal: 4, | ||
getFirstPluginVal() { | ||
return this.myVal // always returns 4 | ||
}, | ||
// this is the first plugin to register this method | ||
// so this is what shows up on the Test object | ||
getFour() { | ||
return 4 | ||
}, | ||
} | ||
} | ||
``` | ||
Only useful if you want a Test without any plugins, for some | ||
reason. | ||
```js | ||
// second-plugin | ||
export const plugin = (t: TestBase) => { | ||
return { | ||
// user will never see this, because first-plugin registered it | ||
myVal: 5, | ||
getSecondPluginValue() { | ||
return this.myVal // always returns 5 | ||
}, | ||
// overridden, this isn't the 'getFour' that the user will see | ||
getFour() { | ||
return 'four' | ||
}, | ||
} | ||
} | ||
``` | ||
## `proc`, `argv`, `cwd`, `env` | ||
Then in the test: | ||
Captured values of `process`, `process.argv`, `process.cwd()`, | ||
and `process.env` at the start of the process, in case they | ||
change later on or are not available for some other reason. | ||
```js | ||
import t from 'tap' | ||
console.log(t.myVal) // 4, not 5 | ||
console.log(t.getFour()) // 4, not 'four' | ||
console.log(t.getFirstPluginVal()) // 4 | ||
console.log(t.getSecondPluginVal()) // 5 | ||
``` | ||
## `tapDir` | ||
## Accessing the Constructed Plugged-In Test Object | ||
The string path to the location of `@tapjs/core`. | ||
If you need access to the constructed `Test` object, you can get | ||
that after the initial plugin load, via `t.t`. However, it will | ||
be `undefined` until all plugins are done loading. | ||
## `mainScript(defaultName = 'TAP'): string` | ||
```js | ||
// my-plugin.ts | ||
export const plugin = (t: TestBase) => { | ||
// here, t.t === undefined | ||
return { | ||
someMethod() { | ||
// here, t.t is the object with all the plugins applied | ||
}, | ||
} | ||
} | ||
``` | ||
The path to the main module that node ran. | ||
## `TapPlugin<PluginValue, OptionsValue>` | ||
The type of a plugin function which returns `PluginValue` and | ||
optionally which takes `OptionsValue` as options. | ||
## `Extra` | ||
The extra info passed to assertions. | ||
Extended by BaseOpts, TestBaseOpts, and ultimately TestOpts, | ||
since any subtest is also an assertion, and can take all the same | ||
assertion options. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
791404
205
9941
96
+ Added@tapjs/stack@0.0.0-5(transitive)
+ Added@tapjs/test@0.0.0-16(transitive)
+ Addedtcompare@6.0.1-4(transitive)
- Removed@tapjs/stack@0.0.0-4(transitive)
- Removed@tapjs/test@0.0.0-15(transitive)
- Removedtcompare@6.0.1-3(transitive)
Updated@tapjs/stack@0.0.0-5
Updated@tapjs/test@0.0.0-16
Updatedtcompare@6.0.1-4