Thingiverse MCP Server

by gpaul-mcp
Verified
import dotenv from 'dotenv'; import path from 'path'; import ThingiversePuppeteer from './thingiverser.class'; const envFile = '.env.development'; dotenv.config({ path: path.resolve(process.cwd(), envFile) }); describe('ThingiversePuppeteer', () => { let puppeteerClient: ThingiversePuppeteer; beforeAll(async () => { const token = process.env.APP_TOKEN; if (!token) { throw new Error('APP_TOKEN environment variable not set'); } puppeteerClient = new ThingiversePuppeteer(token); await puppeteerClient.init(); }, 30000); // Increase timeout for initialization afterAll(async () => { await puppeteerClient.close(); }); test('searchThings returns properly typed data', async () => { const response = await puppeteerClient.searchThings('test'); expect(response).toHaveProperty('hits'); expect(Array.isArray(response.hits)).toBe(true); if (response.hits && response.hits.length > 0) { const hit = response.hits[0]; expect(hit).toHaveProperty('id'); expect(typeof hit.id).toBe('number'); expect(hit).toHaveProperty('name'); expect(typeof hit.name).toBe('string'); expect(hit).toHaveProperty('thumbnail'); } }, 30000); test('searchThings with category ID returns properly typed data', async () => { // First get a valid category const categories = await puppeteerClient.getCategories(); const categoryId = categories[0]?.id?.toString(); if (!categoryId) { console.warn('No categories found to test searchThings with category, skipping test'); return; } const response = await puppeteerClient.searchThings('test', categoryId); expect(response).toHaveProperty('hits'); expect(Array.isArray(response.hits)).toBe(true); if (response.hits && response.hits.length > 0) { const hit = response.hits[0]; expect(hit).toHaveProperty('id'); expect(typeof hit.id).toBe('number'); } }, 30000); test('getFilesFromThing returns properly typed data', async () => { // Get a thing ID from search results const searchResponse = await puppeteerClient.searchThings('test'); const thingId = searchResponse.hits?.[0]?.id; if (!thingId) { console.warn('No search results found to test getFilesFromThing, skipping test'); return; } const files = await puppeteerClient.getFilesFromThing(thingId); expect(Array.isArray(files)).toBe(true); if (files.length > 0) { const file = files[0]; expect(file).toHaveProperty('id'); expect(typeof file.id).toBe('number'); expect(file).toHaveProperty('name'); expect(typeof file.name).toBe('string'); expect(file).toHaveProperty('download_url'); expect(typeof file.download_url).toBe('string'); } }, 30000); test('getRandomThings returns properly typed data', async () => { const things = await puppeteerClient.getRandomThings(); expect(Array.isArray(things)).toBe(true); if (things.length > 0) { const thing = things[0]; expect(thing).toHaveProperty('id'); expect(typeof thing.id).toBe('number'); expect(thing).toHaveProperty('name'); expect(typeof thing.name).toBe('string'); expect(thing).toHaveProperty('thumbnail'); } }, 30000); test('getCategories returns properly typed data', async () => { const categories = await puppeteerClient.getCategories(); expect(Array.isArray(categories)).toBe(true); if (categories.length > 0) { const category = categories[0]; expect(category).toHaveProperty('id'); expect(typeof category.id).toBe('number'); expect(category).toHaveProperty('name'); expect(typeof category.name).toBe('string'); expect(category).toHaveProperty('slug'); expect(typeof category.slug).toBe('string'); } }, 30000); test('getRandomThingsFromCategory returns properly typed data', async () => { // Get a category slug from the categories const categories = await puppeteerClient.getCategories(); const categorySlug = categories[0]?.slug; if (!categorySlug) { console.warn('No categories found to test getRandomThingsFromCategory, skipping test'); return; } const things = await puppeteerClient.getRandomThingsFromCategory(categorySlug); expect(Array.isArray(things)).toBe(true); if (things.length > 0) { const thing = things[0]; expect(thing).toHaveProperty('id'); expect(typeof thing.id).toBe('number'); expect(thing).toHaveProperty('name'); expect(typeof thing.name).toBe('string'); expect(thing).toHaveProperty('thumbnail'); } }, 30000); test('getThingById returns properly typed data', async () => { // Get a thing ID from random things const things = await puppeteerClient.getRandomThings(); const thingId = things[0]?.id; if (!thingId) { console.warn('No random things found to test getThingById, skipping test'); return; } const thing = await puppeteerClient.getThingById(thingId); expect(thing).toBeDefined(); expect(thing).toHaveProperty('id'); expect(thing.id).toBe(thingId); expect(thing).toHaveProperty('name'); expect(typeof thing.name).toBe('string'); expect(thing).toHaveProperty('description'); expect(thing).toHaveProperty('creator'); expect(thing.creator).toHaveProperty('id'); expect(thing.creator).toHaveProperty('name'); }, 30000); test('constructor throws error with missing token', () => { expect(() => new ThingiversePuppeteer('')).toThrow('App token is required'); }); test('makeRequest throws error when browser not initialized', async () => { const newClient = new ThingiversePuppeteer(process.env.TEST || 'dummy-token'); // We're not calling init(), so it should throw await expect(newClient.getCategories()).rejects.toThrow('Browser not initialized'); }); test('handles invalid thing ID gracefully', async () => { await expect(puppeteerClient.getThingById(-1)).rejects.toThrow(); }); });