Adjust tests to use vitest + jsdom
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { expect, test, vi } from "vitest";
|
||||
import { type Cache, memoize, withCache } from "#/engine/lib/cache.ts";
|
||||
import { type Cache, memoize, withCache } from "./cache.ts";
|
||||
|
||||
test("withCache", () => {
|
||||
const cache: Cache<number> = new Map();
|
||||
@@ -31,10 +31,11 @@ test("async withCache", async () => {
|
||||
const callback = withCache(fn, cache);
|
||||
|
||||
const one = "1";
|
||||
const res = await callback("one", one);
|
||||
const _ = await callback("one", one);
|
||||
const res = callback("one", one);
|
||||
const _ = callback("one", one);
|
||||
|
||||
expect(res).toBe(1);
|
||||
expect(res).toBe(_);
|
||||
expect(await res).toBe(1);
|
||||
expect(fn).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(await callback("two", "2")).toBe(2);
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
import type { Circle } from "#/engine/Circle.ts";
|
||||
import type { Rect } from "#/engine/Rect";
|
||||
import type { Vector } from "#/engine/Vector.ts";
|
||||
|
||||
export function isPointInCircle(point: Vector, circle: Circle): boolean {
|
||||
const dx = point.x - circle.position.x;
|
||||
const dy = point.y - circle.position.y;
|
||||
|
||||
return dx * dx + dy * dy <= circle.radius ** 2;
|
||||
}
|
||||
|
||||
export function isPointInRect(point: Vector, rect: Rect): boolean {
|
||||
const rx = rect.position.x;
|
||||
const ry = rect.position.y;
|
||||
|
||||
return (
|
||||
point.x >= rx &&
|
||||
point.x <= rx + rect.width &&
|
||||
point.y >= ry &&
|
||||
point.y <= ry + rect.height
|
||||
);
|
||||
}
|
||||
|
||||
export function circleIntersectCircle(a: Circle, b: Circle): boolean {
|
||||
const dx = a.position.x - b.position.x;
|
||||
const dy = a.position.y - b.position.y;
|
||||
|
||||
return dx * dx + dy * dy <= (a.radius + b.radius) ** 2;
|
||||
}
|
||||
|
||||
export function RectIntersectRect(a: Rect, b: Rect): boolean {
|
||||
const ax = a.position.x;
|
||||
const ay = a.position.y;
|
||||
const bx = b.position.x;
|
||||
const by = b.position.y;
|
||||
|
||||
return (
|
||||
ax <= bx + b.width &&
|
||||
ax + a.width >= bx &&
|
||||
ay <= by + b.height &&
|
||||
ay + a.height >= by
|
||||
);
|
||||
}
|
||||
|
||||
export function circleIntersectRect(circle: Circle, rect: Rect): boolean {
|
||||
const cx = circle.position.x;
|
||||
const cy = circle.position.y;
|
||||
const rx = rect.position.x;
|
||||
const ry = rect.position.y;
|
||||
|
||||
const dx = cx - Math.max(rx, Math.min(cx, rx + rect.width));
|
||||
const dy = cy - Math.max(ry, Math.min(cy, ry + rect.height));
|
||||
|
||||
return dx * dx + dy * dy <= circle.radius ** 2;
|
||||
}
|
||||
|
||||
export function circleContainsCircle(a: Circle, b: Circle): boolean {
|
||||
const dx = a.position.x - b.position.x;
|
||||
const dy = a.position.y - b.position.y;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
|
||||
return a.radius >= b.radius + distance;
|
||||
}
|
||||
|
||||
export function RectContainsRect(a: Rect, b: Rect): boolean {
|
||||
const ax = a.position.x;
|
||||
const ay = a.position.y;
|
||||
const bx = b.position.x;
|
||||
const by = b.position.y;
|
||||
|
||||
return (
|
||||
ax <= bx &&
|
||||
ax + a.width >= bx + b.width &&
|
||||
ay <= by &&
|
||||
ay + a.height >= by + b.height
|
||||
);
|
||||
}
|
||||
|
||||
export function RectContainsCircle(rect: Rect, circle: Circle): boolean {
|
||||
const rx = rect.position.x;
|
||||
const ry = rect.position.y;
|
||||
const cx = circle.position.x;
|
||||
const cy = circle.position.y;
|
||||
|
||||
return (
|
||||
rx <= cx - circle.radius &&
|
||||
rx + rect.width >= cx + circle.radius &&
|
||||
ry <= cy - circle.radius &&
|
||||
ry + rect.height >= cy + circle.radius
|
||||
);
|
||||
}
|
||||
|
||||
export function circleContainsRect(circle: Circle, rect: Rect): boolean {
|
||||
const radSquare = circle.radius ** 2;
|
||||
|
||||
const dax = rect.position.x - circle.position.x;
|
||||
const day = rect.position.y - circle.position.y;
|
||||
if (dax * dax + day * day > radSquare) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const dbx = rect.position.x + rect.width - circle.position.x;
|
||||
const dby = rect.position.y - circle.position.y;
|
||||
if (dbx * dbx + dby * dby > radSquare) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const dcx = rect.position.x - circle.position.x;
|
||||
const dcy = rect.position.y + rect.height - circle.position.y;
|
||||
if (dcx * dcx + dcy * dcy > radSquare) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ddx = rect.position.x + rect.width - circle.position.x;
|
||||
const ddy = rect.position.y + rect.height - circle.position.y;
|
||||
if (ddx * ddx + ddy * ddy > radSquare) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { expect, test } from "vitest";
|
||||
import { lerp, lerpPrecice } from "./lerp.ts";
|
||||
|
||||
test("lerp", () => {
|
||||
const a = 0;
|
||||
const b = 0.1;
|
||||
|
||||
expect(lerp(a, b, 0.2)).toBe(0.020000000000000004);
|
||||
expect(lerp(a, b, 0.5)).toBe(0.05);
|
||||
});
|
||||
|
||||
test("lerpPrecice", () => {
|
||||
const a = 0;
|
||||
const b = 0.1;
|
||||
|
||||
expect(lerpPrecice(a, b, 0.2)).toBe(0.020000000000000004);
|
||||
expect(lerpPrecice(a, b, 0.5)).toBe(0.05);
|
||||
});
|
||||
|
||||
test("lerp vs lerpPrecice", () => {
|
||||
// a and b with very different magnitudes expose
|
||||
// catastrophic cancellation in lerp's `(b - a)` term
|
||||
const a = 1e16;
|
||||
const b = 1;
|
||||
|
||||
// lerp loses b at t = 1
|
||||
expect(lerp(a, b, 1)).toBe(0);
|
||||
|
||||
// lerpPrecice keeps b at t = 1
|
||||
expect(lerpPrecice(a, b, 1)).toBe(b);
|
||||
|
||||
expect(lerp(a, b, 0)).toBe(a);
|
||||
expect(lerpPrecice(a, b, 0)).toBe(a);
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import { afterEach, beforeEach, expect, test } from "vitest";
|
||||
import { loadImage } from "./loadImage.ts";
|
||||
|
||||
class MockImage {
|
||||
static instances: MockImage[] = [];
|
||||
|
||||
onload: (() => void) | null = null;
|
||||
onerror: ((error: unknown) => void) | null = null;
|
||||
src = "";
|
||||
|
||||
constructor() {
|
||||
MockImage.instances.push(this);
|
||||
}
|
||||
}
|
||||
|
||||
const RealImage = globalThis.Image;
|
||||
const realError = console.error;
|
||||
const errors: unknown[][] = [];
|
||||
|
||||
beforeEach(() => {
|
||||
globalThis.Image = MockImage as unknown as typeof Image;
|
||||
console.error = (...args: unknown[]) => {
|
||||
errors.push(args);
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
globalThis.Image = RealImage;
|
||||
console.error = realError;
|
||||
MockImage.instances = [];
|
||||
errors.length = 0;
|
||||
});
|
||||
|
||||
test("loadImage", async () => {
|
||||
const promise = loadImage("image.png");
|
||||
const image = MockImage.instances[0];
|
||||
|
||||
expect(image.src).toBe("image.png");
|
||||
|
||||
image.onload!();
|
||||
|
||||
await expect(promise).resolves.toBe(image);
|
||||
expect(errors).toEqual([]);
|
||||
});
|
||||
|
||||
test("loadImage error", async () => {
|
||||
const promise = loadImage("missing.png");
|
||||
const image = MockImage.instances[0];
|
||||
|
||||
image.onerror!("missing");
|
||||
|
||||
// errors are logged, but the promise still resolves with the image
|
||||
await expect(promise).resolves.toBe(image);
|
||||
expect(errors).toEqual([["missing"]]);
|
||||
});
|
||||
Reference in New Issue
Block a user