Skip to content

Commit 6eb544f

Browse files
committed
progress
1 parent ca78d24 commit 6eb544f

File tree

19 files changed

+1870
-1308
lines changed

19 files changed

+1870
-1308
lines changed

epicshop/package-lock.json

Lines changed: 80 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

epicshop/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44
"@epic-web/workshop-app": "^5.13.6",
55
"@epic-web/workshop-utils": "^5.13.6",
66
"chokidar": "^4.0.3",
7+
"enquirer": "^2.4.1",
78
"execa": "^9.5.2",
9+
"match-sorter": "^8.0.0",
810
"fs-extra": "^11.3.0",
11+
"p-limit": "^6.2.0",
912
"tsx": "^4.19.3"
1013
}
1114
}

exercises/01.start/01.problem/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
"private": true,
44
"type": "module",
55
"scripts": {
6-
"dev": "tsx src/index.ts",
7-
"test": "tsx src/index.test.ts",
8-
"test:watch": "tsx --watch-path=src src/index.test.ts",
6+
"dev:mcp": "tsx src/index.ts",
7+
"test": "vitest",
98
"typecheck": "tsc",
109
"inspect": "mcp-inspector"
1110
},
@@ -19,7 +18,8 @@
1918
"@epic-web/config": "^1.19.0",
2019
"@modelcontextprotocol/inspector": "^0.10.2",
2120
"@types/node": "^22.15.2",
22-
"typescript": "^5.8.3"
21+
"typescript": "^5.8.3",
22+
"vitest": "^3.1.2"
2323
},
2424
"license": "GPL-3.0-only"
2525
}
Lines changed: 25 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import { test, beforeEach, afterEach } from 'node:test'
21
import { invariant } from '@epic-web/invariant'
32
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
43
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'
5-
import { z } from 'zod'
4+
import { test, beforeAll, afterAll, expect } from 'vitest'
65

76
let client: Client
87

9-
beforeEach(async () => {
8+
beforeAll(async () => {
109
client = new Client({
1110
name: 'EpicMathTester',
1211
version: '1.0.0',
@@ -18,36 +17,33 @@ beforeEach(async () => {
1817
await client.connect(transport)
1918
})
2019

21-
afterEach(async () => {
20+
afterAll(async () => {
2221
await client.transport?.close()
2322
})
2423

25-
await test('Tool Definition', async (t) => {
24+
test('Tool Definition', async () => {
2625
const list = await client.listTools()
2726
const [firstTool] = list.tools
2827
invariant(firstTool, '🚨 No tools found')
2928

30-
const expectedToolFormatSchema = z.object({
31-
name: z.string().regex(/^add$/i),
32-
description: z.string().regex(/^add two numbers$/i),
33-
inputSchema: z.object({
34-
type: z.literal('object'),
35-
properties: z.object({
36-
firstNumber: z.object({
37-
type: z.literal('number'),
38-
description: z.string().regex(/first/i),
39-
}),
40-
secondNumber: z.object({
41-
type: z.literal('number'),
42-
description: z.string().regex(/second/i),
29+
expect(firstTool).toEqual(
30+
expect.objectContaining({
31+
name: expect.stringMatching(/^add$/i),
32+
description: expect.stringMatching(/^add two numbers$/i),
33+
inputSchema: expect.objectContaining({
34+
type: 'object',
35+
properties: expect.objectContaining({
36+
firstNumber: expect.objectContaining({
37+
type: 'number',
38+
description: expect.stringMatching(/first/i),
39+
}),
4340
}),
4441
}),
4542
}),
46-
})
47-
assertSchema(expectedToolFormatSchema, firstTool)
43+
)
4844
})
4945

50-
await test('Tool Call', async (t) => {
46+
test('Tool Call', async () => {
5147
const result = await client.callTool({
5248
name: 'add',
5349
arguments: {
@@ -56,26 +52,14 @@ await test('Tool Call', async (t) => {
5652
},
5753
})
5854

59-
assertSchema(
60-
z.object({
61-
content: z.array(
62-
z.object({ type: z.literal('text'), text: z.string().regex(/3/) }),
63-
),
55+
expect(result).toEqual(
56+
expect.objectContaining({
57+
content: expect.arrayContaining([
58+
expect.objectContaining({
59+
type: 'text',
60+
text: expect.stringMatching(/3/),
61+
}),
62+
]),
6463
}),
65-
result,
6664
)
6765
})
68-
69-
// TODO: maybe there's a way within Zod to handle the error message so we can
70-
// just use parse and let it throw its own error.
71-
function assertSchema(
72-
schema: z.ZodSchema,
73-
value: unknown,
74-
): asserts value is z.infer<typeof schema> {
75-
const result = schema.safeParse(value)
76-
if (!result.success) {
77-
console.error('🚨 The following value is invalid:')
78-
console.dir(value, { depth: 8, colors: true })
79-
throw result.error
80-
}
81-
}

exercises/01.start/01.solution/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
"private": true,
44
"type": "module",
55
"scripts": {
6-
"dev": "tsx src/index.ts",
7-
"test": "tsx src/index.test.ts",
8-
"test:watch": "tsx --watch-path=src src/index.test.ts",
6+
"dev:mcp": "tsx src/index.ts",
7+
"test": "vitest",
98
"typecheck": "tsc",
109
"inspect": "mcp-inspector"
1110
},
@@ -19,7 +18,8 @@
1918
"@epic-web/config": "^1.19.0",
2019
"@modelcontextprotocol/inspector": "^0.10.2",
2120
"@types/node": "^22.15.2",
22-
"typescript": "^5.8.3"
21+
"typescript": "^5.8.3",
22+
"vitest": "^3.1.2"
2323
},
2424
"license": "GPL-3.0-only"
2525
}
Lines changed: 25 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import { test, beforeEach, afterEach } from 'node:test'
21
import { invariant } from '@epic-web/invariant'
32
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
43
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'
5-
import { z } from 'zod'
4+
import { test, beforeAll, afterAll, expect } from 'vitest'
65

76
let client: Client
87

9-
beforeEach(async () => {
8+
beforeAll(async () => {
109
client = new Client({
1110
name: 'EpicMathTester',
1211
version: '1.0.0',
@@ -18,36 +17,33 @@ beforeEach(async () => {
1817
await client.connect(transport)
1918
})
2019

21-
afterEach(async () => {
20+
afterAll(async () => {
2221
await client.transport?.close()
2322
})
2423

25-
await test('Tool Definition', async (t) => {
24+
test('Tool Definition', async () => {
2625
const list = await client.listTools()
2726
const [firstTool] = list.tools
2827
invariant(firstTool, '🚨 No tools found')
2928

30-
const expectedToolFormatSchema = z.object({
31-
name: z.string().regex(/^add$/i),
32-
description: z.string().regex(/^add two numbers$/i),
33-
inputSchema: z.object({
34-
type: z.literal('object'),
35-
properties: z.object({
36-
firstNumber: z.object({
37-
type: z.literal('number'),
38-
description: z.string().regex(/first/i),
39-
}),
40-
secondNumber: z.object({
41-
type: z.literal('number'),
42-
description: z.string().regex(/second/i),
29+
expect(firstTool).toEqual(
30+
expect.objectContaining({
31+
name: expect.stringMatching(/^add$/i),
32+
description: expect.stringMatching(/^add two numbers$/i),
33+
inputSchema: expect.objectContaining({
34+
type: 'object',
35+
properties: expect.objectContaining({
36+
firstNumber: expect.objectContaining({
37+
type: 'number',
38+
description: expect.stringMatching(/first/i),
39+
}),
4340
}),
4441
}),
4542
}),
46-
})
47-
assertSchema(expectedToolFormatSchema, firstTool)
43+
)
4844
})
4945

50-
await test('Tool Call', async (t) => {
46+
test('Tool Call', async () => {
5147
const result = await client.callTool({
5248
name: 'add',
5349
arguments: {
@@ -56,26 +52,14 @@ await test('Tool Call', async (t) => {
5652
},
5753
})
5854

59-
assertSchema(
60-
z.object({
61-
content: z.array(
62-
z.object({ type: z.literal('text'), text: z.string().regex(/3/) }),
63-
),
55+
expect(result).toEqual(
56+
expect.objectContaining({
57+
content: expect.arrayContaining([
58+
expect.objectContaining({
59+
type: 'text',
60+
text: expect.stringMatching(/3/),
61+
}),
62+
]),
6463
}),
65-
result,
6664
)
6765
})
68-
69-
// TODO: maybe there's a way within Zod to handle the error message so we can
70-
// just use parse and let it throw its own error.
71-
function assertSchema(
72-
schema: z.ZodSchema,
73-
value: unknown,
74-
): asserts value is z.infer<typeof schema> {
75-
const result = schema.safeParse(value)
76-
if (!result.success) {
77-
console.error('🚨 The following value is invalid:')
78-
console.dir(value, { depth: 8, colors: true })
79-
throw result.error
80-
}
81-
}

0 commit comments

Comments
 (0)