/**
* Live Admin API Integration Tests
*
* Tests against the real Shopify dev store: quick-noshi-dev.myshopify.com
* Requires SHOPIFY_ACCESS_TOKEN env var to be set.
*
* Run with: npx vitest run tests/shopify/live-admin.test.ts
*/
import { ShopifyClient } from '../../src/shopify/client.js';
import { AdminAPI } from '../../src/shopify/admin.js';
// ─── Setup ───
const STORE_DOMAIN = 'quick-noshi-dev.myshopify.com';
const ACCESS_TOKEN = process.env['SHOPIFY_ACCESS_TOKEN'] ?? '';
// Skip all tests if no real token is available
const hasToken = ACCESS_TOKEN.length > 0 && ACCESS_TOKEN !== 'placeholder';
const describeIfToken = hasToken ? describe : describe.skip;
let client: ShopifyClient;
let admin: AdminAPI;
describeIfToken('Live Admin API — quick-noshi-dev', () => {
beforeAll(() => {
client = new ShopifyClient({
storeDomain: STORE_DOMAIN,
accessToken: ACCESS_TOKEN,
storefrontToken: 'unused-for-admin', // Not used for Admin API calls
});
admin = new AdminAPI(client);
});
// ─── Products via Admin (using raw client) ───
describe('Product queries', () => {
it('fetches products from the store', async () => {
const response = await client.adminQuery<{
products: {
edges: Array<{
node: {
id: string;
title: string;
variants: {
edges: Array<{
node: { id: string; title: string; price: string };
}>;
};
};
}>;
};
}>(
`{ products(first: 5) { edges { node { id title variants(first: 1) { edges { node { id title price } } } } } } }`,
);
expect(response.errors).toBeUndefined();
expect(response.data).not.toBeNull();
const products = response.data!.products.edges;
expect(products.length).toBeGreaterThan(0);
// Verify product structure
const first = products[0]!.node;
expect(first.id).toMatch(/^gid:\/\/shopify\/Product\//);
expect(first.title).toBeTruthy();
expect(first.variants.edges.length).toBeGreaterThan(0);
expect(first.variants.edges[0]!.node.id).toMatch(/^gid:\/\/shopify\/ProductVariant\//);
});
it('searches products by title query', async () => {
const response = await client.adminQuery<{
products: {
edges: Array<{
node: { id: string; title: string };
}>;
};
}>(`{ products(first: 5, query: "snowboard") { edges { node { id title } } } }`);
expect(response.errors).toBeUndefined();
expect(response.data).not.toBeNull();
const products = response.data!.products.edges;
expect(products.length).toBeGreaterThan(0);
// At least one product should have "Snowboard" in its title
const hasSnowboard = products.some((p) =>
p.node.title.toLowerCase().includes('snowboard'),
);
expect(hasSnowboard).toBe(true);
});
});
// ─── Inventory ───
describe('Inventory queries', () => {
it('gets inventory level for a known variant', async () => {
// First, get a variant ID from the store
const productsResponse = await client.adminQuery<{
products: {
edges: Array<{
node: {
variants: {
edges: Array<{
node: { id: string };
}>;
};
};
}>;
};
}>(`{ products(first: 1) { edges { node { variants(first: 1) { edges { node { id } } } } } } }`);
const variantId =
productsResponse.data!.products.edges[0]!.node.variants.edges[0]!.node.id;
const inventoryLevel = await admin.getInventoryLevel(variantId);
expect(typeof inventoryLevel).toBe('number');
expect(inventoryLevel).toBeGreaterThanOrEqual(0);
});
it('throws for a nonexistent variant', async () => {
await expect(
admin.getInventoryLevel('gid://shopify/ProductVariant/999999999999'),
).rejects.toThrow();
});
});
// ─── Orders ───
describe('Order queries', () => {
it('fetches recent orders (may be empty on dev store)', async () => {
const orders = await admin.getOrders(5);
expect(Array.isArray(orders)).toBe(true);
// Dev store may not have orders, so just verify the call succeeds
// and returns a valid array
if (orders.length > 0) {
const order = orders[0]!;
expect(order.id).toMatch(/^gid:\/\/shopify\/Order\//);
expect(order.status).toBeTruthy();
expect(order.totals.currency).toBeTruthy();
}
});
it('returns null for a nonexistent order', async () => {
const order = await admin.getOrder('gid://shopify/Order/999999999999');
expect(order).toBeNull();
});
});
// ─── Discount Codes ───
describe('Discount queries', () => {
it('fetches discount codes (may be empty on dev store)', async () => {
const discounts = await admin.getDiscountCodes();
expect(Array.isArray(discounts)).toBe(true);
// Dev store may not have discounts
if (discounts.length > 0) {
const discount = discounts[0]!;
expect(discount.code).toBeTruthy();
expect(['percentage', 'fixed_amount']).toContain(discount.type);
expect(typeof discount.value).toBe('number');
}
});
});
// ─── Rate Limit Headers ───
describe('Rate limiting', () => {
it('stays within rate limits after multiple queries', async () => {
// Make 3 rapid queries and verify no errors
const queries = Array.from({ length: 3 }, () =>
client.adminQuery<{ shop: { name: string } }>(`{ shop { name } }`),
);
const results = await Promise.all(queries);
for (const result of results) {
expect(result.errors).toBeUndefined();
expect(result.data).not.toBeNull();
}
});
});
});