Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 96765f1

Browse files
committed
Setup tests for db queries
1 parent 2d827ec commit 96765f1

File tree

16 files changed

+1998
-86
lines changed

16 files changed

+1998
-86
lines changed

.cursor/rules/bun-tests.mdc

Lines changed: 384 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,384 @@
1+
---
2+
globs: *.test.*
3+
alwaysApply: false
4+
---
5+
6+
This document provides a comprehensive guide for an AI agent to effectively write, run, and manage unit and integration tests for a NextJS/TypeScript SDK project using Bun's built-in test runner.
7+
8+
---
9+
10+
## 🚀 Getting Started
11+
12+
Bun comes with a built-in, Jest-compatible test runner that's incredibly fast. To start, you don't need to install any extra packages. The test runner is part of the `bun` CLI.
13+
14+
### File Discovery
15+
16+
Bun's test runner automatically finds and executes tests in files that match the following patterns anywhere in your project:
17+
18+
- `*.test.{js|jsx|ts|tsx}`
19+
- `*_test.{js|jsx|ts|tsx}`
20+
- `*.spec.{js|jsx|ts|tsx}`
21+
- `*_spec.{js|jsx|ts|tsx}`
22+
23+
### Running Tests
24+
25+
Execute tests using the `bun test` command.
26+
27+
```shell
28+
# Run all tests in the project
29+
bun test
30+
31+
# Run all tests within a specific directory (by path fragment)
32+
bun test <directory_name>
33+
34+
# Run a specific test file (by path fragment)
35+
bun test <filename_fragment>
36+
37+
# Run a specific test file by its exact path
38+
bun test ./tests/specific-file.test.ts
39+
```
40+
41+
---
42+
43+
## ✍️ Writing Tests
44+
45+
Bun's test runner is designed to be a drop-in replacement for Jest. It uses a familiar `describe`, `test`, and `expect` API.
46+
47+
### Basic Test Structure
48+
49+
Tests are defined with the `test()` function (or its alias `it()`) and grouped into suites with `describe()`. Assertions are made using `expect()`.
50+
51+
```typescript
52+
// Import test utilities from bun:test
53+
import { test, expect, describe } from "bun:test";
54+
55+
describe("SDK Math Utilities", () => {
56+
// A simple synchronous test
57+
test("should add two numbers correctly", () => {
58+
expect(2 + 2).toBe(4);
59+
});
60+
61+
// An asynchronous test using async/await
62+
test("should resolve a promise", async () => {
63+
const result = await Promise.resolve("hello");
64+
expect(result).toEqual("hello");
65+
});
66+
});
67+
```
68+
69+
### Assertions with `expect`
70+
71+
Bun implements the full Jest `expect` API. Here are some common matchers:
72+
73+
- `.toBe(value)`: Strict equality (`===`).
74+
- `.toEqual(value)`: Deep equality for objects and arrays.
75+
- `.toThrow(error?)`: Checks if a function throws an error.
76+
- `.toHaveBeenCalled()`: For checking if a mock function was called.
77+
- `.toHaveBeenCalledWith(...args)`: Checks arguments passed to a mock.
78+
- `.toMatchSnapshot()`: Performs snapshot testing.
79+
- `.toMatchInlineSnapshot()`: Performs inline snapshot testing.
80+
81+
You can also verify that a certain number of assertions were called, which is useful in asynchronous code.
82+
83+
```typescript
84+
test("should run a specific number of assertions", () => {
85+
expect.hasAssertions(); // Ensures at least one assertion is called
86+
expect.assertions(2); // Ensures exactly two assertions are called
87+
88+
expect(1).toBe(1);
89+
expect(true).not.toBe(false);
90+
});
91+
```
92+
93+
### Parametrized Tests with `.each`
94+
95+
Run the same test logic with different data using `test.each` or `describe.each`. This is ideal for data-driven testing.
96+
97+
```typescript
98+
const additionCases = [
99+
[1, 2, 3],
100+
[0, 0, 0],
101+
[-5, 5, 0],
102+
];
103+
104+
test.each(additionCases)("add(%i, %i) should equal %i", (a, b, expected) => {
105+
expect(a + b).toBe(expected);
106+
});
107+
```
108+
109+
---
110+
111+
## 🔬 Advanced Testing Techniques
112+
113+
### Mocking
114+
115+
#### Mocking Functions
116+
117+
Use `mock()` to create a mock function. This allows you to track calls, arguments, and return values.
118+
119+
```typescript
120+
import { test, expect, mock } from "bun:test";
121+
122+
const getAPIData = mock((id: string) => ({ id, data: "some data" }));
123+
124+
test("API data fetching", () => {
125+
const result = getAPIData("user-123");
126+
127+
expect(getAPIData).toHaveBeenCalled();
128+
expect(getAPIData).toHaveBeenCalledTimes(1);
129+
expect(getAPIData).toHaveBeenCalledWith("user-123");
130+
expect(result.data).toBe("some data");
131+
});
132+
```
133+
134+
#### Spying on Methods
135+
136+
Use `spyOn()` to track calls to an existing object's method without replacing its original implementation.
137+
138+
```typescript
139+
import { test, expect, spyOn } from "bun:test";
140+
141+
const analyticsService = {
142+
trackEvent(eventName: string) {
143+
console.log(`Event tracked: ${eventName}`);
144+
},
145+
};
146+
147+
test("should track events", () => {
148+
const spy = spyOn(analyticsService, "trackEvent");
149+
150+
analyticsService.trackEvent("sdk_initialized");
151+
152+
expect(spy).toHaveBeenCalledTimes(1);
153+
expect(spy).toHaveBeenCalledWith("sdk_initialized");
154+
});
155+
```
156+
157+
#### Mocking Modules
158+
159+
To mock an entire module, create a preload script and tell Bun to load it before running tests.
160+
161+
1. **Create the preload script:**
162+
163+
```typescript
164+
// mocks/my-module-mock.ts
165+
import { mock } from "bun:test";
166+
167+
mock.module("./path/to/original-module", () => {
168+
return {
169+
default: () => "mocked function result",
170+
someNamedExport: "mocked value",
171+
};
172+
});
173+
```
174+
175+
2. **Run tests with the `--preload` flag:**
176+
```shell
177+
bun test --preload ./mocks/my-module-mock.ts
178+
```
179+
3. **Or configure it in `bunfig.toml`:**
180+
```toml
181+
[test]
182+
preload = ["./mocks/my-module-mock.ts"]
183+
```
184+
185+
### Snapshot Testing
186+
187+
Snapshot tests are useful for ensuring that large objects or UI components don't change unexpectedly.
188+
189+
```typescript
190+
import { test, expect } from "bun:test";
191+
192+
test("SDK configuration object snapshot", () => {
193+
const config = {
194+
apiKey: "key-123",
195+
retries: 3,
196+
features: {
197+
featureA: true,
198+
featureB: false,
199+
},
200+
};
201+
// On the first run, this creates a .snap file.
202+
// On subsequent runs, it compares the object to the saved snapshot.
203+
expect(config).toMatchSnapshot();
204+
});
205+
206+
test("inline snapshot", () => {
207+
// The snapshot is written directly into the test file by Bun.
208+
expect({ foo: "bar" }).toMatchInlineSnapshot(`
209+
{
210+
"foo": "bar",
211+
}
212+
`);
213+
});
214+
```
215+
216+
To update snapshots if the change is intentional:
217+
218+
```shell
219+
bun test --update-snapshots
220+
```
221+
222+
### DOM Testing for NextJS Components
223+
224+
For testing NextJS components, you'll need a DOM environment and a testing library.
225+
226+
1. **Install Dependencies:**
227+
228+
```shell
229+
bun add -D @happy-dom/global-registrator @testing-library/react @testing-library/jest-dom
230+
```
231+
232+
2. **Create a Preload Script for Setup:** Create two files to configure the environment.
233+
234+
```typescript
235+
// tests/setup/happydom.ts
236+
import { GlobalRegistrator } from "@happy-dom/global-registrator";
237+
GlobalRegistrator.register();
238+
```
239+
240+
```typescript
241+
// tests/setup/testing-library.ts
242+
import { afterEach, expect } from "bun:test";
243+
import { cleanup } from "@testing-library/react";
244+
import * as matchers from "@testing-library/jest-dom/matchers";
245+
246+
// Extend Bun's expect with Jest-DOM matchers
247+
expect.extend(matchers);
248+
249+
// Clean up the DOM after each test
250+
afterEach(() => {
251+
cleanup();
252+
});
253+
```
254+
255+
3. **Configure `bunfig.toml`:**
256+
257+
```toml
258+
[test]
259+
preload = ["./tests/setup/happydom.ts", "./tests/setup/testing-library.ts"]
260+
```
261+
262+
4. **Write a Component Test:** Now you can write tests for your React components.
263+
264+
```tsx
265+
// components/MyComponent.test.tsx
266+
import { test, expect } from "bun:test";
267+
import { render, screen } from "@testing-library/react";
268+
import MyComponent from "./MyComponent"; // Your React component
269+
270+
test("MyComponent should render correctly", () => {
271+
render(<MyComponent />);
272+
const element = screen.getByText("Hello from Component");
273+
expect(element).toBeInTheDocument();
274+
});
275+
```
276+
277+
---
278+
279+
## ⚙️ Configuration and CLI
280+
281+
### Controlling Test Execution
282+
283+
- **Run only specific tests:** Use `.only` on `test` or `describe` blocks.
284+
285+
```typescript
286+
test.only("this test will run", () => {});
287+
test("this test will be skipped", () => {});
288+
```
289+
290+
To run all tests marked with `.only`, use the `--only` flag: `bun test --only`.
291+
292+
- **Skip tests:** Use `.skip` to temporarily disable tests.
293+
294+
```typescript
295+
test.skip("this test is skipped", () => {});
296+
```
297+
298+
- **Filter by name:** Run tests whose name matches a pattern.
299+
300+
```shell
301+
bun test -t "should add"
302+
```
303+
304+
- **Bail on failure:** Stop the test run after a certain number of failures.
305+
306+
```shell
307+
bun test --bail # Stop after the first failure
308+
bun test --bail=3 # Stop after 3 failures
309+
```
310+
311+
- **Set timeouts:** Change the default 5-second timeout.
312+
313+
```shell
314+
# Set timeout via CLI for all tests
315+
bun test --timeout 10000 # 10 seconds
316+
317+
# Set timeout for a specific test
318+
test("long running task", async () => {
319+
// ...
320+
}, 30000); // 30s timeout for this test
321+
```
322+
323+
### Watch Mode
324+
325+
For rapid development, run tests in watch mode to automatically re-run them on file changes.
326+
327+
```shell
328+
bun test --watch
329+
```
330+
331+
### Code Coverage
332+
333+
Generate a code coverage report using the `--coverage` flag.
334+
335+
```shell
336+
bun test --coverage
337+
```
338+
339+
You can configure coverage options in `bunfig.toml`.
340+
341+
```toml
342+
[test]
343+
# Always generate coverage
344+
coverage = true
345+
346+
# Set a minimum coverage threshold (e.g., 80%)
347+
# The test run will fail if coverage is below this value.
348+
coverageThreshold = 0.8
349+
350+
# Exclude test files from the coverage report
351+
coverageSkipTestFiles = true
352+
```
353+
354+
---
355+
356+
## 🔄 CI/CD Integration
357+
358+
To integrate Bun tests into a CI pipeline like GitHub Actions, you can use a workflow like this:
359+
360+
```yaml
361+
# .github/workflows/test.yml
362+
jobs:
363+
test:
364+
name: Run Tests
365+
runs-on: ubuntu-latest
366+
steps:
367+
- name: Checkout
368+
uses: actions/checkout@v4
369+
370+
- name: Install Bun
371+
uses: oven-sh/setup-bun@v2
372+
373+
- name: Install Dependencies
374+
run: bun install
375+
376+
- name: Run Tests
377+
run: bun test
378+
```
379+
380+
For more detailed reporting in CI systems, you can generate a JUnit XML report.
381+
382+
```shell
383+
bun test --reporter=junit --reporter-outfile=./junit-report.xml
384+
```

0 commit comments

Comments
 (0)