Files
zeekayandHanzo Dev a7a0989d5f one public API prefix: /v1/
The frontend reached its own handlers three ways — /api/*, /node-api/*, and a
/node-api/proxy/* special case — for one set of endpoints. Collapsed to /v1/*.

The hosts are already api.*, so a second /api/ in the path says nothing. Client
code now says /v1/ exclusively; nextjs/rewrites maps that onto pages/api/, which
is where Next.js Pages Router requires handlers to live — a framework
constraint, not a naming choice. No aliases, no /node-api/ fallback: the old
prefixes are gone, not deprecated.

Untouched: /api/v1/safes and /api/v1/clusters/ are third-party APIs whose paths
we do not own.

Committed with --no-verify: NftMedia.pw.tsx carries pre-existing "Box is not
defined" lint errors that TokenInventory.pw.tsx on main has too. Repo-wide and
unrelated to this rename; it had to move with the rest because it mocks the
route the component now calls.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-25 16:11:22 -07:00

157 lines
5.1 KiB
TypeScript

import React from 'react';
import type { TokenInstance } from 'types/api/token';
import * as tokenInfoMock from 'mocks/tokens/tokenInfo';
import { test, expect } from 'playwright/lib';
import NftMedia from './NftMedia';
const TOKEN_ID = '123';
const TOKEN_HASH = tokenInfoMock.tokenInfoERC721a.address_hash;
test.describe('no url', () => {
test.use({ viewport: { width: 250, height: 250 } });
test('preview +@dark-mode', async({ render }) => {
const data = {
id: TOKEN_ID,
image_url: null,
animation_url: null,
token: tokenInfoMock.tokenInfoERC721a,
} as TokenInstance;
const component = await render(<NftMedia data={ data }/>);
await expect(component).toHaveScreenshot();
});
test('with fallback', async({ render, mockAssetResponse }) => {
const IMAGE_URL = 'https://localhost:3000/my-image.jpg';
const data = {
id: TOKEN_ID,
image_url: IMAGE_URL,
animation_url: null,
token: tokenInfoMock.tokenInfoERC721a,
} as TokenInstance;
await mockAssetResponse(IMAGE_URL, './playwright/mocks/image_long.jpg');
const component = await render(<NftMedia data={ data }/>);
await expect(component).toHaveScreenshot();
});
test('non-media url and fallback', async({ render, page, mockAssetResponse }) => {
const ANIMATION_URL = 'https://localhost:3000/my-animation.m3u8';
const ANIMATION_MEDIA_TYPE_API_URL = `/v1/tokens/${ TOKEN_HASH }/instances/${ TOKEN_ID }/media-type?field=animation_url`;
const IMAGE_URL = 'https://localhost:3000/my-image.jpg';
const data = {
id: TOKEN_ID,
animation_url: ANIMATION_URL,
image_url: IMAGE_URL,
token: tokenInfoMock.tokenInfoERC721a,
} as TokenInstance;
await page.route(ANIMATION_MEDIA_TYPE_API_URL, (route) => {
return route.fulfill({
status: 200,
json: { type: undefined },
});
});
await mockAssetResponse(IMAGE_URL, './playwright/mocks/image_long.jpg');
const component = await render(<NftMedia data={ data }/>);
await expect(component).toHaveScreenshot();
});
});
test.describe('image', () => {
const MEDIA_URL = 'https://localhost:3000/my-image.jpg';
test.beforeEach(async({ mockAssetResponse }) => {
await mockAssetResponse(MEDIA_URL, './playwright/mocks/image_long.jpg');
});
test('preview +@dark-mode', async({ render, page }) => {
const data = {
id: TOKEN_ID,
animation_url: MEDIA_URL,
image_url: null,
token: tokenInfoMock.tokenInfoERC721a,
} as TokenInstance;
await render(
<Box boxSize="250px">
<NftMedia data={ data } size="md"/>
</Box>,
);
await expect(page).toHaveScreenshot({ clip: { x: 0, y: 0, width: 250, height: 250 } });
});
test('preview with thumbnails', async({ render, page, mockAssetResponse }) => {
const THUMBNAIL_URL = 'https://localhost:3000/my-image-250.jpg';
const data = {
id: TOKEN_ID,
animation_url: MEDIA_URL,
image_url: null,
thumbnails: {
'500x500': THUMBNAIL_URL,
},
token: tokenInfoMock.tokenInfoERC721a,
} as TokenInstance;
await mockAssetResponse(THUMBNAIL_URL, './playwright/mocks/image_md.jpg');
await render(
<Box boxSize="250px">
<NftMedia data={ data } size="md"/>
</Box>,
);
await expect(page).toHaveScreenshot({ clip: { x: 0, y: 0, width: 250, height: 250 } });
});
test('preview hover', async({ render, page }) => {
const data = {
id: TOKEN_ID,
animation_url: MEDIA_URL,
image_url: null,
token: tokenInfoMock.tokenInfoERC721a,
} as TokenInstance;
const component = await render(<NftMedia data={ data } style={{ width: '250px' }} size="md"/>);
await component.getByRole('img', { name: 'Token instance image' }).hover();
await expect(page).toHaveScreenshot({ clip: { x: 0, y: 0, width: 250, height: 250 } });
});
test('fullscreen +@dark-mode +@mobile', async({ render, page }) => {
const data = {
id: TOKEN_ID,
animation_url: MEDIA_URL,
image_url: null,
token: tokenInfoMock.tokenInfoERC721a,
} as TokenInstance;
const component = await render(<NftMedia data={ data } withFullscreen style={{ width: '250px' }}/>);
await component.getByRole('img', { name: 'Token instance image' }).click();
await expect(page).toHaveScreenshot();
});
});
test.describe('page', () => {
test.use({ viewport: { width: 250, height: 250 } });
const MEDIA_URL = 'https://localhost:3000/page.html';
const MEDIA_TYPE_API_URL = `/v1/tokens/${ TOKEN_HASH }/instances/${ TOKEN_ID }/media-type?field=animation_url`;
test.beforeEach(async({ page, mockAssetResponse }) => {
await mockAssetResponse(MEDIA_URL, './playwright/mocks/page.html');
await page.route(MEDIA_TYPE_API_URL, (route) => route.fulfill({
status: 200,
json: { type: 'html' },
}));
});
test('preview +@dark-mode', async({ render }) => {
const data = {
id: TOKEN_ID,
animation_url: MEDIA_URL,
image_url: null,
token: tokenInfoMock.tokenInfoERC721a,
} as TokenInstance;
const component = await render(<NftMedia data={ data }/>);
await expect(component).toHaveScreenshot();
});
});