Skip to content

Add try-commit to test assertions #1947

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

Merged
merged 113 commits into from
Sep 8, 2019
Merged
Show file tree
Hide file tree
Changes from 94 commits
Commits
Show all changes
113 commits
Select commit Hold shift + click to select a range
40fa08e
Add try-commit to test assertions
qlonik Oct 6, 2018
2521b31
Don't use rest symbol to support Node 6
qlonik Oct 7, 2018
8afddc2
Update TS typings with t.try()
qlonik Oct 8, 2018
d64a6fb
Refactor tryTest: pull toCommit() defn from promise
qlonik Oct 10, 2018
fccf41b
Make sure commit()/discard() only called once
qlonik Oct 10, 2018
d1d559f
No need to save return error of attempt twice
qlonik Oct 10, 2018
6be281f
Use rest and spread on arguments to try function
qlonik Jan 15, 2019
eeb861b
Count pending before executing passed fn
qlonik Jan 15, 2019
7153337
Make behaviour of try more implicit
qlonik Jan 15, 2019
62ffd9b
Return array of assertion errors from commit()
qlonik Jan 15, 2019
ba690b7
Fix tests of the test class
qlonik Jan 15, 2019
a4f0fee
Fix error message when test finished early
qlonik Jan 15, 2019
7750dfc
Save logs from discard if needed
qlonik Jan 20, 2019
476148c
Remove discard before promise resolved
qlonik Jan 20, 2019
42a7245
Move attempt counting into Test class
qlonik Jan 20, 2019
e71ee0b
Add optional title to attempt
qlonik Jan 20, 2019
a5f0772
Fix errors in strings returned to a user
qlonik Jan 28, 2019
eb49df2
Add documentation to AttemptReturnValue
qlonik Jan 28, 2019
a22e97c
Rename AttemptReturnValue into AttemptResult
qlonik Jan 28, 2019
46772a7
Test snapshots as part of try-commit
qlonik Jan 28, 2019
40ede92
Format with xo
qlonik Jan 28, 2019
fd7be32
Adjust TypeScript definition
novemberborn Feb 10, 2019
279057f
Remove (currently) unnecessary check for test results containing mult…
novemberborn Feb 10, 2019
ed5db80
Count number of assertions performed in subtest
qlonik Mar 17, 2019
51323c1
Fix error where failed attempt was not discarded
qlonik Mar 17, 2019
fe8ebf8
Adjust test counting number of assertions performed
qlonik Mar 17, 2019
c28152f
Always fail when there are some non committed/discarded attempts
qlonik Mar 17, 2019
7fa7cf5
Add support for macros passed to attempt
qlonik Mar 17, 2019
95c8585
Make sure try-commit follows timeout settings
qlonik Mar 17, 2019
b43626d
Get rid of runtime conditional types
qlonik Mar 17, 2019
226044c
Type try fn to accept macros
qlonik Mar 17, 2019
c9643f7
Add macro test with parameter inference
qlonik Mar 17, 2019
cc5d4ae
Test types of try fn
qlonik Mar 18, 2019
5384876
Add new metadata type: inline
qlonik Apr 1, 2019
786a446
Fix complicated if-else statement
qlonik Apr 1, 2019
6533c76
Fix test to check assertCount instead of attemptCount
qlonik Apr 1, 2019
42f4b7c
Add test checking that .end() is not allowed inside try-commit
qlonik Apr 1, 2019
6b4dc21
Move ava test initializer into helper file
qlonik Apr 1, 2019
92ff524
Move try-commit tests into separate file
qlonik Apr 1, 2019
19c8d88
Check t.try is properly bound
qlonik Apr 6, 2019
fa7204c
Make sure inline test cannot access context
qlonik Apr 8, 2019
d627b13
Merge branch 'master' into test-try-commit-assertion
qlonik Apr 23, 2019
23fe80c
Fix exported name of attempt function
qlonik Apr 23, 2019
dc3060f
Use async/await in try implementation
qlonik Apr 23, 2019
be19cb8
Use object spread instead of Object.assign
qlonik Apr 23, 2019
ea65141
Fix error where `this` was used instead of `test`
qlonik Apr 23, 2019
f20495e
Merge branch 'master' into test-try-commit-assertion
novemberborn May 31, 2019
87603f5
Remove TryFn#skip() from type definition
novemberborn May 31, 2019
38c5bee
Change AssertionError to an interface
novemberborn May 31, 2019
8a6de55
Tweak type definition & comments
novemberborn May 31, 2019
f8c6bb1
Document metadata.inline
novemberborn May 31, 2019
bffb7a7
Reuse test argument parsing logic
novemberborn May 31, 2019
aca1d64
Single quotes
novemberborn May 31, 2019
5c31c1e
Fix result typing when t.try() is called with an array of implementat…
novemberborn May 31, 2019
6385ea1
Merge branch 'master' into test-try-commit-assertion
novemberborn Jun 1, 2019
e3f9b7c
Copy the context ref when building the attempt test
novemberborn Jun 1, 2019
4cbf0e1
t.try() attempts can never be marked as failing. Override metadata fr…
novemberborn Jun 1, 2019
ded6e4b
t.try() attempts can never use callback mode. Override metedata from …
novemberborn Jun 1, 2019
a14459f
Tweak error thrown when using t.end() inside a t.try()
novemberborn Jun 1, 2019
e5229d1
Untangle logic in verifyAssertion(), add some comments
novemberborn Jun 1, 2019
a3b0f88
Reorder Test property initializations
novemberborn Jun 1, 2019
6408c10
Refactor test title building and validation
novemberborn Jun 1, 2019
d2b85da
Ensure `t.try()` titles are unique
novemberborn Jun 1, 2019
2d6cb65
Refactor t.try() implementation
novemberborn Jun 1, 2019
c68deca
Make Context optional in TryFn interface
novemberborn Jun 2, 2019
8767cf9
Change default type of Context to 'unknown'
novemberborn Jun 2, 2019
b9dbadb
Copy logs that are exposed as the attempt result
novemberborn Jun 3, 2019
b325cde
Rename AttemptResult to TryResult
novemberborn Jun 3, 2019
30e522a
Only record snapshots when attempt is committed
novemberborn Jun 3, 2019
fcbffb7
Fix detection of callback test that ended with pending assertions rem…
novemberborn Jun 3, 2019
34bc3d4
Merge branch 'master' into test-try-commit-assertion
novemberborn Jun 16, 2019
bc1c951
Just pass an array to parseTestArgs
novemberborn Jun 16, 2019
31be1f7
Fix regressions introduced by parseTestArgs extraction
novemberborn Jun 16, 2019
c5c5f00
Remove call to removed fn addPendingAttemptAssertion
qlonik Jul 1, 2019
a01d4e0
Store registerUniqueTitle() on test instance from options
qlonik Jul 1, 2019
5baf9ad
Add dummy impl of registerUniqueTitle to tests
qlonik Jul 1, 2019
589e332
Use real ContextRef in test instead of dummy
qlonik Jul 1, 2019
40765fc
Pass real ContextRef instance at call-site in test-try-commit
qlonik Jul 1, 2019
edaf7fe
Fix try result resolution when passing array of test fns
qlonik Jul 1, 2019
7f489b5
Return assertCount value from run()
qlonik Jul 1, 2019
b2e9e80
Adjust test titles in try-commit title check
qlonik Jul 1, 2019
10ec2f5
Remove redundant error message check
qlonik Jul 1, 2019
89f6a5a
Adjust test to access parent context since it is allowed now
qlonik Jul 1, 2019
64461ff
Extract context data into variable in test checking context
qlonik Jul 1, 2019
cdf3403
Remove unused variable in test-try-commit
qlonik Jul 1, 2019
506bddf
Allow creating new snapshots with the value of updating
qlonik Jul 2, 2019
4f42253
Pass real contextRef and dummy registerUniqueTitle()
qlonik Jul 2, 2019
a374981
Allow passing title of the test per test case
qlonik Jul 2, 2019
2b537bb
Create not equal amount of snapshots in each attempt
qlonik Jul 2, 2019
a6fe8d2
Refactor try-snapshot test to have one snapshot manager
qlonik Jul 2, 2019
a7e2a7f
Add missing nextSnapshotIndex update when committing to attempt
qlonik Jul 2, 2019
5e87468
Update expected snapshot result
qlonik Jul 2, 2019
6d72cb0
Remove unneeded logging of failed test
qlonik Jul 2, 2019
9b41685
Update expectation for test with concurrent attempts
qlonik Jul 2, 2019
e5913f8
Merge branch 'master' into test-try-commit-assertion
novemberborn Jul 14, 2019
aca26c7
Remove unnecessary presence test
qlonik Jul 14, 2019
8abeb18
Switch try-snapshot tests to use async-await
qlonik Jul 14, 2019
3b677ae
Inline attempt functions in try call
qlonik Jul 14, 2019
6a7114d
Clarify title for failing test with try-commit
qlonik Jul 14, 2019
7b3a698
Remove test which no longer applies
qlonik Jul 14, 2019
ec00c90
Convert tests to use async-await
qlonik Jul 14, 2019
c17d2ab
Rename tests as suggested by novemberborn
qlonik Jul 14, 2019
d64c8d4
Add test cases suggested by novemberborn
qlonik Jul 14, 2019
2e624e1
Check that assert within attempt does not refresh test timeout
qlonik Jul 14, 2019
9503cb6
Merge branch 'test-try-commit-assertion' of https://github.com/qlonik…
novemberborn Aug 18, 2019
1652c4e
Merge branch 'master' into test-try-commit-assertion
novemberborn Aug 18, 2019
d26575e
Report pending attempts or assertions before verifying whether there …
novemberborn Aug 18, 2019
1920792
Attempts count as a single assertion for parent tests
novemberborn Aug 18, 2019
16cc21e
Fix error when an asynchronous assertion is started after the test ha…
novemberborn Aug 18, 2019
bb458be
Assertions must not be run outside of an active attempt
novemberborn Aug 18, 2019
c302923
Mark t.try() as experimental in the type definition
novemberborn Aug 18, 2019
fa7812d
Merge branch 'master' into test-try-commit-assertion
novemberborn Sep 8, 2019
2b8ba3a
Require opt-in for t.try()
novemberborn Sep 8, 2019
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
117 changes: 94 additions & 23 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ export type ThrowsExpectation = {
name?: string;
};

export type CommitDiscardOptions = {
/**
* Whether the logs should be included in those of the parent test.
*/
retainLogs?: boolean
}

/** Options that can be passed to the `t.snapshot()` assertion. */
export type SnapshotOptions = {
/** If provided and not an empty string, used to select the snapshot to compare the `expected` value against. */
Expand Down Expand Up @@ -353,7 +360,7 @@ export interface TruthyAssertion {
}

/** The `t` value passed to test & hook implementations. */
export interface ExecutionContext<Context = {}> extends Assertions {
export interface ExecutionContext<Context = unknown> extends Assertions {
/** Test context, shared with hooks. */
context: Context;

Expand All @@ -363,6 +370,7 @@ export interface ExecutionContext<Context = {}> extends Assertions {
log: LogFn;
plan: PlanFn;
timeout: TimeoutFn;
try: TryFn<Context>;
}

export interface LogFn {
Expand Down Expand Up @@ -392,8 +400,71 @@ export interface TimeoutFn {
(ms: number): void;
}

export interface TryFn<Context = unknown> {
/**
* Attempt to run some assertions. The result must be explicitly committed or discarded or else
* the test will fail. A macro may be provided. The title may help distinguish attempts from
* one another.
*/
<Args extends any[]>(title: string, fn: EitherMacro<Args, Context>, ...args: Args): Promise<TryResult>;

/**
* Attempt to run some assertions. The result must be explicitly committed or discarded or else
* the test will fail. A macro may be provided. The title may help distinguish attempts from
* one another.
*/
<Args extends any[]>(title: string, fn: [EitherMacro<Args, Context>, ...EitherMacro<Args, Context>[]], ...args: Args): Promise<TryResult[]>;

/**
* Attempt to run some assertions. The result must be explicitly committed or discarded or else
* the test will fail. A macro may be provided.
*/
<Args extends any[]>(fn: EitherMacro<Args, Context>, ...args: Args): Promise<TryResult>;

/**
* Attempt to run some assertions. The result must be explicitly committed or discarded or else
* the test will fail. A macro may be provided.
*/
<Args extends any[]>(fn: [EitherMacro<Args, Context>, ...EitherMacro<Args, Context>[]], ...args: Args): Promise<TryResult[]>;
}

export interface AssertionError extends Error {}

export interface TryResult {
/**
* Title of the attempt, helping you tell attempts aparts.
*/
title: string;

/**
* Indicates whether all assertions passed, or at least one failed.
*/
passed: boolean;

/**
* Errors raised for each failed assertion.
*/
errors: AssertionError[];

/**
* Logs created during the attempt using `t.log()`. Contains formatted values.
*/
logs: string[];

/**
* Commit the attempt. Counts as one assertion for the plan count. If the
* attempt failed, calling this will also cause your test to fail.
*/
commit(options?: CommitDiscardOptions): void;

/**
* Discard the attempt.
*/
discard(options?: CommitDiscardOptions): void;
}

/** The `t` value passed to implementations for tests & hooks declared with the `.cb` modifier. */
export interface CbExecutionContext<Context = {}> extends ExecutionContext<Context> {
export interface CbExecutionContext<Context = unknown> extends ExecutionContext<Context> {
/**
* End the test. If `error` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) the test or hook
* will fail.
Expand All @@ -402,14 +473,14 @@ export interface CbExecutionContext<Context = {}> extends ExecutionContext<Conte
}

export type ImplementationResult = PromiseLike<void> | ObservableLike | void;
export type Implementation<Context = {}> = (t: ExecutionContext<Context>) => ImplementationResult;
export type CbImplementation<Context = {}> = (t: CbExecutionContext<Context>) => ImplementationResult;
export type Implementation<Context = unknown> = (t: ExecutionContext<Context>) => ImplementationResult;
export type CbImplementation<Context = unknown> = (t: CbExecutionContext<Context>) => ImplementationResult;

/** A reusable test or hook implementation. */
export type UntitledMacro<Args extends any[], Context = {}> = (t: ExecutionContext<Context>, ...args: Args) => ImplementationResult;
export type UntitledMacro<Args extends any[], Context = unknown> = (t: ExecutionContext<Context>, ...args: Args) => ImplementationResult;

/** A reusable test or hook implementation. */
export type Macro<Args extends any[], Context = {}> = UntitledMacro<Args, Context> & {
export type Macro<Args extends any[], Context = unknown> = UntitledMacro<Args, Context> & {
/**
* Implement this function to generate a test (or hook) title whenever this macro is used. `providedTitle` contains
* the title provided when the test or hook was declared. Also receives the remaining test arguments.
Expand All @@ -423,10 +494,10 @@ export type EitherMacro<Args extends any[], Context> = Macro<Args, Context> | Un
export type OneOrMoreMacros<Args extends any[], Context> = EitherMacro<Args, Context> | [EitherMacro<Args, Context>, ...EitherMacro<Args, Context>[]];

/** A reusable test or hook implementation, for tests & hooks declared with the `.cb` modifier. */
export type UntitledCbMacro<Args extends any[], Context = {}> = (t: CbExecutionContext<Context>, ...args: Args) => ImplementationResult
export type UntitledCbMacro<Args extends any[], Context = unknown> = (t: CbExecutionContext<Context>, ...args: Args) => ImplementationResult

/** A reusable test or hook implementation, for tests & hooks declared with the `.cb` modifier. */
export type CbMacro<Args extends any[], Context = {}> = UntitledCbMacro<Args, Context> & {
export type CbMacro<Args extends any[], Context = unknown> = UntitledCbMacro<Args, Context> & {
title?: (providedTitle: string | undefined, ...args: Args) => string;
}

Expand All @@ -435,7 +506,7 @@ export type EitherCbMacro<Args extends any[], Context> = CbMacro<Args, Context>
/** Alias for a single macro, or an array of macros, used for tests & hooks declared with the `.cb` modifier. */
export type OneOrMoreCbMacros<Args extends any[], Context> = EitherCbMacro<Args, Context> | [EitherCbMacro<Args, Context>, ...EitherCbMacro<Args, Context>[]];

export interface TestInterface<Context = {}> {
export interface TestInterface<Context = unknown> {
/** Declare a concurrent test. */
(title: string, implementation: Implementation<Context>): void;

Expand Down Expand Up @@ -472,7 +543,7 @@ export interface TestInterface<Context = {}> {
meta: MetaInterface;
}

export interface AfterInterface<Context = {}> {
export interface AfterInterface<Context = unknown> {
/** Declare a hook that is run once, after all tests have passed. */
(implementation: Implementation<Context>): void;

Expand All @@ -494,7 +565,7 @@ export interface AfterInterface<Context = {}> {
skip: HookSkipInterface<Context>;
}

export interface AlwaysInterface<Context = {}> {
export interface AlwaysInterface<Context = unknown> {
/** Declare a hook that is run once, after all tests are done. */
(implementation: Implementation<Context>): void;

Expand All @@ -513,7 +584,7 @@ export interface AlwaysInterface<Context = {}> {
skip: HookSkipInterface<Context>;
}

export interface BeforeInterface<Context = {}> {
export interface BeforeInterface<Context = unknown> {
/** Declare a hook that is run once, before all tests. */
(implementation: Implementation<Context>): void;

Expand All @@ -532,7 +603,7 @@ export interface BeforeInterface<Context = {}> {
skip: HookSkipInterface<Context>;
}

export interface CbInterface<Context = {}> {
export interface CbInterface<Context = unknown> {
/** Declare a test that must call `t.end()` when it's done. */
(title: string, implementation: CbImplementation<Context>): void;

Expand All @@ -555,7 +626,7 @@ export interface CbInterface<Context = {}> {
skip: CbSkipInterface<Context>;
}

export interface CbFailingInterface<Context = {}> {
export interface CbFailingInterface<Context = unknown> {
/** Declare a test that must call `t.end()` when it's done. The test is expected to fail. */
(title: string, implementation: CbImplementation<Context>): void;

Expand All @@ -575,7 +646,7 @@ export interface CbFailingInterface<Context = {}> {
skip: CbSkipInterface<Context>;
}

export interface CbOnlyInterface<Context = {}> {
export interface CbOnlyInterface<Context = unknown> {
/**
* Declare a test that must call `t.end()` when it's done. Only this test and others declared with `.only()` are run.
*/
Expand All @@ -594,7 +665,7 @@ export interface CbOnlyInterface<Context = {}> {
<T extends any[]>(macros: OneOrMoreCbMacros<T, Context>, ...rest: T): void;
}

export interface CbSkipInterface<Context = {}> {
export interface CbSkipInterface<Context = unknown> {
/** Skip this test. */
(title: string, implementation: CbImplementation<Context>): void;

Expand All @@ -605,7 +676,7 @@ export interface CbSkipInterface<Context = {}> {
<T extends any[]>(macros: OneOrMoreCbMacros<T, Context>, ...rest: T): void;
}

export interface FailingInterface<Context = {}> {
export interface FailingInterface<Context = unknown> {
/** Declare a concurrent test. The test is expected to fail. */
(title: string, implementation: Implementation<Context>): void;

Expand All @@ -625,7 +696,7 @@ export interface FailingInterface<Context = {}> {
skip: SkipInterface<Context>;
}

export interface HookCbInterface<Context = {}> {
export interface HookCbInterface<Context = unknown> {
/** Declare a hook that must call `t.end()` when it's done. */
(implementation: CbImplementation<Context>): void;

Expand All @@ -646,7 +717,7 @@ export interface HookCbInterface<Context = {}> {
skip: HookCbSkipInterface<Context>;
}

export interface HookCbSkipInterface<Context = {}> {
export interface HookCbSkipInterface<Context = unknown> {
/** Skip this hook. */
(implementation: CbImplementation<Context>): void;

Expand All @@ -660,7 +731,7 @@ export interface HookCbSkipInterface<Context = {}> {
<T extends any[]>(macros: OneOrMoreCbMacros<T, Context>, ...rest: T): void;
}

export interface HookSkipInterface<Context = {}> {
export interface HookSkipInterface<Context = unknown> {
/** Skip this hook. */
(implementation: Implementation<Context>): void;

Expand All @@ -674,7 +745,7 @@ export interface HookSkipInterface<Context = {}> {
<T extends any[]>(macros: OneOrMoreMacros<T, Context>, ...rest: T): void;
}

export interface OnlyInterface<Context = {}> {
export interface OnlyInterface<Context = unknown> {
/** Declare a test. Only this test and others declared with `.only()` are run. */
(title: string, implementation: Implementation<Context>): void;

Expand All @@ -691,7 +762,7 @@ export interface OnlyInterface<Context = {}> {
<T extends any[]>(macros: OneOrMoreMacros<T, Context>, ...rest: T): void;
}

export interface SerialInterface<Context = {}> {
export interface SerialInterface<Context = unknown> {
/** Declare a serial test. */
(title: string, implementation: Implementation<Context>): void;

Expand Down Expand Up @@ -726,7 +797,7 @@ export interface SerialInterface<Context = {}> {
todo: TodoDeclaration;
}

export interface SkipInterface<Context = {}> {
export interface SkipInterface<Context = unknown> {
/** Skip this test. */
(title: string, implementation: Implementation<Context>): void;

Expand Down
15 changes: 15 additions & 0 deletions lib/parse-test-args.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use strict';
function parseTestArgs(args) {
const rawTitle = typeof args[0] === 'string' ? args.shift() : undefined;
const receivedImplementationArray = Array.isArray(args[0]);
const implementations = receivedImplementationArray ? args.shift() : args.splice(0, 1);

const buildTitle = implementation => {
const title = implementation.title ? implementation.title(rawTitle, ...args) : rawTitle;
return {title, isSet: typeof title !== 'undefined', isValid: typeof title === 'string', isEmpty: !title};
};

return {args, buildTitle, implementations, rawTitle, receivedImplementationArray};
}

module.exports = parseTestArgs;
Loading