mirror of
https://github.com/gosticks/DefinitelyTyped.git
synced 2026-06-28 14:20:12 +00:00
feat: Add type definitions for npm module ospec (#37645)
* feat: Add type definitions for npm module `ospec` * Apply suggestions from code review Co-Authored-By: Isiah Meadows <contact@isiahmeadows.com> * fix: Disable no-unnecessary-generics for dummy o.spy() generation * fix: Rename namespace to match thew global export's name * fix: Properly guard against non-newable functions ...and relax TypeScript version requirement to 3.1 * feat: Simplify the assertion signature * fix: Error in `tslint:disable` syntax * feat: Make .notEquals() and .notDeepEquals() type safe * feat: Update the `Definer` type... * Allow tests to return any `PromiseLike` objects. * Disallow anything but Error and null as argument for `done()` * feat: Add tests for Definer` functions returning promises * style: Prefer `import o = require('')` over `import o from` in test file
This commit is contained in:
committed by
Sheetal Nandi
parent
a9950fcb4a
commit
4b29f4bd1d
92
types/ospec/index.d.ts
vendored
Normal file
92
types/ospec/index.d.ts
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
// Type definitions for ospec 4.0
|
||||
// Project: https://github.com/MithrilJS/mithril.js/tree/next/ospec
|
||||
// Definitions by: Már Örlygsson <https://github.com/maranomynet>
|
||||
// Mike Linkovich <https://github.com/spacejack>
|
||||
// Isiah Meadows <https://github.com/isiahmeadows>
|
||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||
// TypeScript Version: 3.1
|
||||
|
||||
type ObjectConstructor = new (...args: any[]) => any;
|
||||
|
||||
declare namespace o {
|
||||
type AssertionDescriber = (description: string) => void;
|
||||
|
||||
interface Spy<Args extends any[], Returns> {
|
||||
(...args: Args): Returns;
|
||||
/** The number of times the function has been called */
|
||||
readonly callCount: number;
|
||||
/** The arguments that were passed to the function in the last time it was called */
|
||||
readonly args: Args;
|
||||
/** List of arguments that were passed to the function each tine it was called */
|
||||
readonly calls: Args[];
|
||||
}
|
||||
|
||||
interface Assertion<T> {
|
||||
/** Asserts that two values are strictly equal */
|
||||
equals(expected: T): AssertionDescriber;
|
||||
/** Asserts that two values are **not** strictly equal */
|
||||
notEquals(value: T): AssertionDescriber;
|
||||
|
||||
/** Asserts that two objects are recursively equal */
|
||||
deepEquals(this: Assertion<object>, expected: T): AssertionDescriber;
|
||||
/** Asserts that two objects are **not** recursively equal */
|
||||
notDeepEquals(this: Assertion<object>, value: T): AssertionDescriber;
|
||||
|
||||
/** Asserts that the function throws an error of a given type */
|
||||
throws(this: Assertion<() => any>, error: string | ObjectConstructor): AssertionDescriber;
|
||||
/** Asserts that the function does **not** throw an error of given type */
|
||||
notThrows(this: Assertion<() => any>, error: string | ObjectConstructor): AssertionDescriber; // See above
|
||||
}
|
||||
|
||||
type Definer = (done: (error?: Error | null) => void, timeout: (delay: number) => void) => void | PromiseLike<any>;
|
||||
|
||||
interface Result {
|
||||
pass: boolean | null;
|
||||
context: string;
|
||||
message: string;
|
||||
error: Error | null;
|
||||
testError: Error | null;
|
||||
}
|
||||
|
||||
type Reporter = (results: Result[]) => number;
|
||||
|
||||
interface Ospec {
|
||||
/** Starts an assertion */
|
||||
<T>(actual: T): Assertion<T>;
|
||||
|
||||
/** Defines a test */
|
||||
(name: string, assertions: Definer): void;
|
||||
|
||||
/** Defines a group of tests */
|
||||
spec(name: string, tests: () => void): void;
|
||||
|
||||
/** Defines code to be run at the beginning of a test group */
|
||||
before(setup: Definer): void;
|
||||
/** Defines code to be run before each test in a group */
|
||||
beforeEach(teardown: Definer): void;
|
||||
/** Defines code to be run at the end of a test group */
|
||||
after(setup: Definer): void;
|
||||
/** Defines code to be run after each test in a group */
|
||||
afterEach(teardown: Definer): void;
|
||||
|
||||
/** Returns a function that records the number of times it gets called, and its arguments */
|
||||
spy<A extends any[]>(): Spy<A, undefined>; // tslint:disable-line:no-unnecessary-generics
|
||||
spy<A extends any[], R>(fn: (...args: A) => R): Spy<A, R>;
|
||||
|
||||
/** Amount of time (in milliseconds) to wait until bailing out of a test */
|
||||
timeout(delay: number): void;
|
||||
/** Configure the default amount of time (in milliseconds) to wait until bailing out of a group of tests */
|
||||
specTimeout(delay: number): void;
|
||||
|
||||
/** Runs the test suite */
|
||||
run(reporter?: Reporter): void;
|
||||
/** Default reporter used by `o.run()` */
|
||||
report: Reporter;
|
||||
|
||||
'new'(): Ospec;
|
||||
}
|
||||
}
|
||||
|
||||
declare const o: o.Ospec;
|
||||
export = o;
|
||||
export as namespace o;
|
||||
243
types/ospec/ospec-tests.ts
Normal file
243
types/ospec/ospec-tests.ts
Normal file
@@ -0,0 +1,243 @@
|
||||
import o = require('ospec');
|
||||
// import o, { Definer } from 'ospec'; // NOTE: this only works with "esModuleInterop": true
|
||||
|
||||
const exampleTypeUse1: o.Definer = () => {};
|
||||
// const exampleTypeUse2: Definer = () => {}; // NOTE: this only works with "esModuleInterop": true
|
||||
|
||||
// ======================================================================
|
||||
|
||||
// $ExpectType void
|
||||
o.spec('ospec typings', () => {
|
||||
const bool = false;
|
||||
const numOrStr = Date.now() > 0 ? 'hi' : 42;
|
||||
const obj = { a: 1 };
|
||||
const arr = [1];
|
||||
const fn = () => {};
|
||||
|
||||
// $ExpectType void
|
||||
o('o(actual) returns assertion interface based on input type', () => {
|
||||
o(bool); // $ExpectType Assertion<boolean>
|
||||
o(numOrStr); // $ExpectType Assertion<string | number>
|
||||
o(arr); // $ExpectType Assertion<number[]>
|
||||
o(obj); // $ExpectType Assertion<{ a: number; }>
|
||||
o(new Date()); // $ExpectType Assertion<Date>
|
||||
o(fn); // $ExpectType Assertion<() => void>
|
||||
});
|
||||
|
||||
o('.equals() is type safe', () => {
|
||||
o(bool).equals(true); // $ExpectType AssertionDescriber
|
||||
o(bool).equals(true)('description text');
|
||||
o(numOrStr).equals('hello');
|
||||
o(numOrStr).equals(1);
|
||||
o(fn).equals(() => {});
|
||||
o(obj).equals({ a: 1 });
|
||||
o(arr).equals([1, 2]);
|
||||
|
||||
// $ExpectError
|
||||
o(bool).equals(1);
|
||||
// $ExpectError
|
||||
o(numOrStr).equals(true);
|
||||
// $ExpectError
|
||||
o(fn).equals(1);
|
||||
// $ExpectError
|
||||
o(obj).equals({});
|
||||
// $ExpectError
|
||||
o(arr).equals(['hi']);
|
||||
});
|
||||
|
||||
o('.notEquals() is also type safe', () => {
|
||||
o(bool).notEquals(true); // $ExpectType AssertionDescriber
|
||||
o(bool).notEquals(true)('description text');
|
||||
o(numOrStr).notEquals('hello');
|
||||
o(numOrStr).notEquals(1);
|
||||
o(fn).notEquals(() => {});
|
||||
o(obj).notEquals({ a: 1 });
|
||||
o(arr).notEquals([1, 2]);
|
||||
|
||||
// $ExpectError
|
||||
o(bool).notEquals(1);
|
||||
// $ExpectError
|
||||
o(numOrStr).notEquals(true);
|
||||
// $ExpectError
|
||||
o(fn).notEquals(1);
|
||||
// $ExpectError
|
||||
o(obj).notEquals({});
|
||||
// $ExpectError
|
||||
o(arr).notEquals(['hi']);
|
||||
});
|
||||
|
||||
o('.deepEquals()/.notDeepEquals() only compares objects to object values', () => {
|
||||
o(obj).deepEquals({
|
||||
a: 1,
|
||||
});
|
||||
o(arr).deepEquals([1]); // $ExpectType AssertionDescriber
|
||||
o(fn).deepEquals(() => {}); // $ExpectType AssertionDescriber
|
||||
o(obj).notDeepEquals({
|
||||
a: 1,
|
||||
});
|
||||
o(arr).notDeepEquals([1]); // $ExpectType AssertionDescriber
|
||||
o(fn).notDeepEquals(() => {}); // $ExpectType AssertionDescriber
|
||||
|
||||
// $ExpectError
|
||||
o(obj).deepEquals(1);
|
||||
// $ExpectError
|
||||
o(obj).notDeepEquals(1);
|
||||
// $ExpectError
|
||||
o(bool).deepEquals(1);
|
||||
// $ExpectError
|
||||
o(bool).notDeepEquals(1);
|
||||
// $ExpectError
|
||||
o(numOrStr).deepEquals(1);
|
||||
// $ExpectError
|
||||
o(numOrStr).notDeepEquals(1);
|
||||
// $ExpectError
|
||||
o(obj).notDeepEquals({});
|
||||
// $ExpectError
|
||||
o(arr).notDeepEquals(['hi']); // $ExpectType AssertionDescriber
|
||||
// $ExpectError
|
||||
o(fn).notDeepEquals({}); // $ExpectType AssertionDescriber
|
||||
});
|
||||
|
||||
o('.throws()/.notThrows() only available for function values', () => {
|
||||
o(fn).throws('baz'); // $ExpectType AssertionDescriber
|
||||
o(fn).notThrows('baz'); // $ExpectType AssertionDescriber
|
||||
o(fn).throws(Error);
|
||||
// NOTE: ospec says trows/notThrows accepts "Object constructor"
|
||||
o(fn).notThrows(String);
|
||||
|
||||
// $ExpectError
|
||||
o(bool).throws('baz');
|
||||
// $ExpectError
|
||||
o(bool).notThrows('baz');
|
||||
|
||||
// `expected` must only be string or "Object constructor"
|
||||
// $ExpectError
|
||||
o(fn).throws(1);
|
||||
// $ExpectError
|
||||
o(fn).throws(1);
|
||||
|
||||
const nonNewableFn = () => {};
|
||||
// $ExpectError
|
||||
o(fn).throws(nonNewableFn);
|
||||
// $ExpectError
|
||||
o(fn).notThrows(nonNewableFn);
|
||||
});
|
||||
|
||||
// ======================================================================
|
||||
|
||||
const dummySpy = o.spy();
|
||||
dummySpy();
|
||||
const {
|
||||
callCount, // $ExpectType number
|
||||
args, // $ExpectType any[]
|
||||
calls, // $ExpectType any[][]
|
||||
} = dummySpy;
|
||||
|
||||
const myFunc = (a: string, b?: boolean) => 42;
|
||||
const spiedFunc = o.spy(myFunc);
|
||||
type SpiedFuncParams = Parameters<typeof spiedFunc>; // $ExpectType [string, (boolean | undefined)?]
|
||||
const _args1: SpiedFuncParams = ['hi', true];
|
||||
const _args2: SpiedFuncParams = ['hi'];
|
||||
spiedFunc(..._args1); // $ExpectType number
|
||||
spiedFunc(..._args2); // $ExpectType number
|
||||
spiedFunc.args; // $ExpectType [string, (boolean | undefined)?]
|
||||
spiedFunc.calls; // $ExpectType [string, (boolean | undefined)?][]
|
||||
|
||||
// ======================================================================
|
||||
|
||||
let definerFn: o.Definer;
|
||||
definerFn = () => {};
|
||||
definerFn = done => {
|
||||
done(); // $ExpectType void
|
||||
done(new Error('err'));
|
||||
done(null);
|
||||
|
||||
// $ExpectError
|
||||
done('Error message');
|
||||
// $ExpectError
|
||||
done(1);
|
||||
// $ExpectError
|
||||
done(null, null);
|
||||
};
|
||||
definerFn = (_, timeout) => {
|
||||
timeout(42); // $ExpectType void
|
||||
|
||||
// $ExpectError
|
||||
timeout();
|
||||
// $ExpectError
|
||||
timeout('42');
|
||||
// $ExpectError
|
||||
timeout(1, 2);
|
||||
};
|
||||
|
||||
// Tests may return a promise-like value instead of calling done()
|
||||
definerFn = () => {
|
||||
return Promise.resolve('Whatever');
|
||||
};
|
||||
definerFn = (done, timeout) => {
|
||||
timeout(9000);
|
||||
// TODO: Find a way to discourage the use of done() in promise returning tests
|
||||
// $_ExpectError
|
||||
done();
|
||||
return Promise.resolve('Whatever');
|
||||
};
|
||||
|
||||
o('async tests', definerFn);
|
||||
o.before(definerFn); // $ExpectType void
|
||||
o.after(definerFn); // $ExpectType void
|
||||
o.beforeEach(definerFn); // $ExpectType void
|
||||
o.afterEach(definerFn); // $ExpectType void
|
||||
|
||||
// ======================================================================
|
||||
|
||||
o.specTimeout(42); // $ExpectType void
|
||||
// $ExpectError
|
||||
o.specTimeout();
|
||||
// $ExpectError
|
||||
o.specTimeout('42');
|
||||
|
||||
o('async test timeout', _ => {
|
||||
o.timeout(42); // $ExpectType void
|
||||
|
||||
// $ExpectError
|
||||
o.timeout();
|
||||
// $ExpectError
|
||||
o.timeout('42');
|
||||
});
|
||||
|
||||
// ======================================================================
|
||||
|
||||
const myReporter: o.Reporter = results => {
|
||||
const myResult = results[0]; // $ExpectType Result
|
||||
return 0;
|
||||
};
|
||||
|
||||
o.report = myReporter;
|
||||
// $ExpectError
|
||||
o.report = fn;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
o.run(); // $ExpectType void
|
||||
o.run(myReporter);
|
||||
// $ExpectError
|
||||
o.run(true);
|
||||
// $ExpectError
|
||||
o.run(fn);
|
||||
|
||||
// ======================================================================
|
||||
|
||||
const o2: o.Ospec = o.new();
|
||||
o2.spec('New Ospec instance', () => {
|
||||
o2('Works?', done => {
|
||||
o2('Yes').equals('Yes');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// $ExpectError
|
||||
o.new(true);
|
||||
});
|
||||
|
||||
// $ExpectError
|
||||
o.spec(() => {}); // Missing name parameter
|
||||
23
types/ospec/tsconfig.json
Normal file
23
types/ospec/tsconfig.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"lib": [
|
||||
"es6"
|
||||
],
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"strictFunctionTypes": true,
|
||||
"strictNullChecks": true,
|
||||
"baseUrl": "../",
|
||||
"typeRoots": [
|
||||
"../"
|
||||
],
|
||||
"types": [],
|
||||
"noEmit": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"files": [
|
||||
"index.d.ts",
|
||||
"ospec-tests.ts"
|
||||
]
|
||||
}
|
||||
1
types/ospec/tslint.json
Normal file
1
types/ospec/tslint.json
Normal file
@@ -0,0 +1 @@
|
||||
{ "extends": "dtslint/dt.json" }
|
||||
Reference in New Issue
Block a user