Thingiverse MCP Server
by gpaul-mcp
Verified
- MCP_thingiverse
- src
- class
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();
});
});