wip:milestone 0 fixes
Some checks failed
CI/CD Pipeline / unit-tests (push) Failing after 1m16s
CI/CD Pipeline / integration-tests (push) Failing after 2m32s
CI/CD Pipeline / lint (push) Successful in 5m22s
CI/CD Pipeline / e2e-tests (push) Has been skipped
CI/CD Pipeline / build (push) Has been skipped

This commit is contained in:
2026-03-15 12:35:42 +02:00
parent 6708cf28a7
commit cffdf8af86
61266 changed files with 4511646 additions and 1938 deletions

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Tinylibs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,11 @@
# tinyspy
> minimal fork of nanospy, with more features 🕵🏻‍♂️
A `10KB` package for minimal and easy testing with no dependencies.
This package was created for having a tiny spy library to use in `vitest`, but it can also be used in `jest` and other test environments.
_In case you need more tiny libraries like tinypool or tinyspy, please consider submitting an [RFC](https://github.com/tinylibs/rfcs)_
## Docs
Read full docs **[here](https://github.com/tinylibs/tinyspy#readme)**.

View File

@@ -0,0 +1,84 @@
declare const SYMBOL_STATE: unique symbol;
interface GetState {
<A extends any[], R>(spy: SpyInternalImpl<A, R>): SpyInternalImplState<A, R>;
<A extends any[], R>(spy: SpyInternal<A, R>): SpyInternalState<A, R>;
}
declare let spies: Set<SpyImpl<any[], any>>;
declare let getInternalState: GetState;
type ReturnError = ['error', any];
type ReturnOk<R> = ['ok', R];
type ResultFn<R> = ReturnError | ReturnOk<R>;
interface SpyInternal<A extends any[] = any[], R = any> {
(this: any, ...args: A): R;
[SYMBOL_STATE]: SpyInternalState<A, R>;
}
interface SpyInternalImpl<A extends any[] = any[], R = any> extends SpyInternal<A, R> {
[SYMBOL_STATE]: SpyInternalImplState<A, R>;
}
interface SpyInternalState<A extends any[] = any[], R = any> {
called: boolean;
callCount: number;
calls: A[];
results: ResultFn<R>[];
resolves: R extends PromiseLike<infer V> ? ResultFn<V>[] : never;
reset(): void;
impl: ((...args: A) => R) | undefined;
next: ResultFn<R>[];
}
interface SpyInternalImplState<A extends any[] = any[], R = any> extends SpyInternalState<A, R> {
getOriginal(): (...args: A) => R;
willCall(cb: (...args: A) => R): this;
restore(): void;
}
interface Spy<A extends any[] = any[], R = any> extends SpyInternalState<A, R> {
(this: any, ...args: A): R;
returns: R[];
length: number;
nextError(error: any): this;
nextResult(result: R): this;
}
interface SpyImpl<A extends any[] = any[], R = any> extends Spy<A, R> {
getOriginal(): (...args: A) => R;
willCall(cb: (...args: A) => R): this;
restore(): void;
}
declare function createInternalSpy<A extends any[], R>(cb?: ((...args: A) => R) | {
new (...args: A): R;
}): SpyInternal<A, R>;
interface SpyFn<A extends any[] = any[], R = any> extends Spy<A, R> {
new (...args: A): R extends void ? any : R;
(...args: A): R;
}
declare function spy<A extends any[], R>(cb?: ((...args: A) => R) | {
new (...args: A): R;
}): SpyFn<A, R>;
type Procedure = (...args: any[]) => any;
type Methods<T> = {
[K in keyof T]: T[K] extends Procedure ? K : never;
}[keyof T];
type Getters<T> = {
[K in keyof T]: T[K] extends Procedure ? never : K;
}[keyof T];
type Constructors<T> = {
[K in keyof T]: T[K] extends new (...args: any[]) => any ? K : never;
}[keyof T];
declare function internalSpyOn<T, K extends string & keyof T>(obj: T, methodName: K | {
getter: K;
} | {
setter: K;
}, mock?: Procedure): SpyInternalImpl<any[], any>;
declare function spyOn<T, S extends Getters<Required<T>>>(obj: T, methodName: {
setter: S;
}, mock?: (arg: T[S]) => void): SpyImpl<[T[S]], void>;
declare function spyOn<T, G extends Getters<Required<T>>>(obj: T, methodName: {
getter: G;
}, mock?: () => T[G]): SpyImpl<[], T[G]>;
declare function spyOn<T, M extends Constructors<Required<T>>>(object: T, method: M): Required<T>[M] extends new (...args: infer A) => infer R ? SpyImpl<A, R> : never;
declare function spyOn<T, M extends Methods<Required<T>>>(obj: T, methodName: M, mock?: T[M]): Required<T>[M] extends (...args: infer A) => infer R ? SpyImpl<A, R> : never;
declare function restoreAll(): void;
export { type Spy, type SpyFn, type SpyImpl, type SpyInternal, type SpyInternalImpl, createInternalSpy, getInternalState, internalSpyOn, restoreAll, spies, spy, spyOn };

View File

@@ -0,0 +1,202 @@
// src/utils.ts
function S(e, t) {
if (!e)
throw new Error(t);
}
function f(e, t) {
return typeof t === e;
}
function w(e) {
return e instanceof Promise;
}
function u(e, t, r) {
Object.defineProperty(e, t, r);
}
function l(e, t, r) {
u(e, t, { value: r, configurable: !0, writable: !0 });
}
// src/constants.ts
var y = Symbol.for("tinyspy:spy");
// src/internal.ts
var x = /* @__PURE__ */ new Set(), h = (e) => {
e.called = !1, e.callCount = 0, e.calls = [], e.results = [], e.resolves = [], e.next = [];
}, k = (e) => (u(e, y, {
value: { reset: () => h(e[y]) }
}), e[y]), T = (e) => e[y] || k(e);
function R(e) {
S(
f("function", e) || f("undefined", e),
"cannot spy on a non-function value"
);
let t = function(...s) {
let n = T(t);
n.called = !0, n.callCount++, n.calls.push(s);
let d = n.next.shift();
if (d) {
n.results.push(d);
let [a, i] = d;
if (a === "ok")
return i;
throw i;
}
let o, c = "ok", p = n.results.length;
if (n.impl)
try {
new.target ? o = Reflect.construct(n.impl, s, new.target) : o = n.impl.apply(this, s), c = "ok";
} catch (a) {
throw o = a, c = "error", n.results.push([c, a]), a;
}
let g = [c, o];
return w(o) && o.then(
(a) => n.resolves[p] = ["ok", a],
(a) => n.resolves[p] = ["error", a]
), n.results.push(g), o;
};
l(t, "_isMockFunction", !0), l(t, "length", e ? e.length : 0), l(t, "name", e && e.name || "spy");
let r = T(t);
return r.reset(), r.impl = e, t;
}
function v(e) {
return !!e && e._isMockFunction === !0;
}
function A(e) {
let t = T(e);
"returns" in e || (u(e, "returns", {
get: () => t.results.map(([, r]) => r)
}), [
"called",
"callCount",
"results",
"resolves",
"calls",
"reset",
"impl"
].forEach(
(r) => u(e, r, { get: () => t[r], set: (s) => t[r] = s })
), l(e, "nextError", (r) => (t.next.push(["error", r]), t)), l(e, "nextResult", (r) => (t.next.push(["ok", r]), t)));
}
// src/spy.ts
function Y(e) {
let t = R(e);
return A(t), t;
}
// src/spyOn.ts
var b = (e, t) => {
let r = Object.getOwnPropertyDescriptor(e, t);
if (r)
return [e, r];
let s = Object.getPrototypeOf(e);
for (; s !== null; ) {
let n = Object.getOwnPropertyDescriptor(s, t);
if (n)
return [s, n];
s = Object.getPrototypeOf(s);
}
}, P = (e, t) => {
t != null && typeof t == "function" && t.prototype != null && Object.setPrototypeOf(e.prototype, t.prototype);
};
function M(e, t, r) {
S(
!f("undefined", e),
"spyOn could not find an object to spy upon"
), S(
f("object", e) || f("function", e),
"cannot spyOn on a primitive value"
);
let [s, n] = (() => {
if (!f("object", t))
return [t, "value"];
if ("getter" in t && "setter" in t)
throw new Error("cannot spy on both getter and setter");
if ("getter" in t)
return [t.getter, "get"];
if ("setter" in t)
return [t.setter, "set"];
throw new Error("specify getter or setter to spy on");
})(), [d, o] = b(e, s) || [];
S(
o || s in e,
`${String(s)} does not exist`
);
let c = !1;
n === "value" && o && !o.value && o.get && (n = "get", c = !0, r = o.get());
let p;
o ? p = o[n] : n !== "value" ? p = () => e[s] : p = e[s], p && j(p) && (p = p[y].getOriginal());
let g = (I) => {
let { value: F, ...O } = o || {
configurable: !0,
writable: !0
};
n !== "value" && delete O.writable, O[n] = I, u(e, s, O);
}, a = () => {
d !== e ? Reflect.deleteProperty(e, s) : o && !p ? u(e, s, o) : g(p);
};
r || (r = p);
let i = E(R(r), r);
n === "value" && P(i, p);
let m = i[y];
return l(m, "restore", a), l(m, "getOriginal", () => c ? p() : p), l(m, "willCall", (I) => (m.impl = I, i)), g(
c ? () => (P(i, r), i) : i
), x.add(i), i;
}
var K = /* @__PURE__ */ new Set([
"length",
"name",
"prototype"
]);
function D(e) {
let t = /* @__PURE__ */ new Set(), r = {};
for (; e && e !== Object.prototype && e !== Function.prototype; ) {
let s = [
...Object.getOwnPropertyNames(e),
...Object.getOwnPropertySymbols(e)
];
for (let n of s)
r[n] || K.has(n) || (t.add(n), r[n] = Object.getOwnPropertyDescriptor(e, n));
e = Object.getPrototypeOf(e);
}
return {
properties: t,
descriptors: r
};
}
function E(e, t) {
if (!t || // the original is already a spy, so it has all the properties
y in t)
return e;
let { properties: r, descriptors: s } = D(t);
for (let n of r) {
let d = s[n];
b(e, n) || u(e, n, d);
}
return e;
}
function Z(e, t, r) {
let s = M(e, t, r);
return A(s), ["restore", "getOriginal", "willCall"].forEach((n) => {
l(s, n, s[y][n]);
}), s;
}
function j(e) {
return v(e) && "getOriginal" in e[y];
}
// src/restoreAll.ts
function te() {
for (let e of x)
e.restore();
x.clear();
}
export {
R as createInternalSpy,
T as getInternalState,
M as internalSpyOn,
te as restoreAll,
x as spies,
Y as spy,
Z as spyOn
};

View File

@@ -0,0 +1,37 @@
{
"name": "tinyspy",
"type": "module",
"version": "4.0.4",
"packageManager": "pnpm@9.1.1",
"description": "A minimal fork of nanospy, with more features",
"license": "MIT",
"homepage": "https://github.com/tinylibs/tinyspy#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/tinylibs/tinyspy.git"
},
"bugs": {
"url": "https://github.com/tinylibs/tinyspy/issues"
},
"keywords": [
"spy",
"mock",
"typescript",
"method"
],
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"engines": {
"node": ">=14.0.0"
}
}