Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/build-lint-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ on:
required: true
SECURITY_ALERTS_API_BASE_URL:
required: true
NFT_API_BASE_URL:
required: true
EXPLORER_BASE_URL:
required: true

Expand Down Expand Up @@ -65,6 +67,7 @@ jobs:
TOKEN_API_BASE_URL: ${{ secrets.TOKEN_API_BASE_URL }}
STATIC_API_BASE_URL: ${{ secrets.STATIC_API_BASE_URL }}
SECURITY_ALERTS_API_BASE_URL: ${{ secrets.SECURITY_ALERTS_API_BASE_URL }}
NFT_API_BASE_URL: ${{ secrets.NFT_API_BASE_URL }}
steps:
- name: Checkout and setup environment
uses: MetaMask/action-checkout-and-setup@v1
Expand Down Expand Up @@ -116,6 +119,7 @@ jobs:
TOKEN_API_BASE_URL: ${{ secrets.TOKEN_API_BASE_URL }}
STATIC_API_BASE_URL: ${{ secrets.STATIC_API_BASE_URL }}
SECURITY_ALERTS_API_BASE_URL: ${{ secrets.SECURITY_ALERTS_API_BASE_URL }}
NFT_API_BASE_URL: ${{ secrets.NFT_API_BASE_URL }}
steps:
- name: Checkout and setup environment
uses: MetaMask/action-checkout-and-setup@v1
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/create-release-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,4 @@ jobs:
TOKEN_API_BASE_URL: ${{ secrets.TOKEN_API_BASE_URL }}
STATIC_API_BASE_URL: ${{ secrets.STATIC_API_BASE_URL }}
SECURITY_ALERTS_API_BASE_URL: ${{ secrets.SECURITY_ALERTS_API_BASE_URL }}
NFT_API_BASE_URL: ${{ secrets.NFT_API_BASE_URL }}
2 changes: 2 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ jobs:
TOKEN_API_BASE_URL: ${{ secrets.TOKEN_API_BASE_URL }}
STATIC_API_BASE_URL: ${{ secrets.STATIC_API_BASE_URL }}
SECURITY_ALERTS_API_BASE_URL: ${{ secrets.SECURITY_ALERTS_API_BASE_URL }}
NFT_API_BASE_URL: ${{ secrets.NFT_API_BASE_URL }}

sonarcloud:
permissions:
Expand Down Expand Up @@ -101,3 +102,4 @@ jobs:
TOKEN_API_BASE_URL: ${{ secrets.TOKEN_API_BASE_URL }}
STATIC_API_BASE_URL: ${{ secrets.STATIC_API_BASE_URL }}
SECURITY_ALERTS_API_BASE_URL: ${{ secrets.SECURITY_ALERTS_API_BASE_URL }}
NFT_API_BASE_URL: ${{ secrets.NFT_API_BASE_URL }}
1 change: 1 addition & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
TOKEN_API_BASE_URL: ${{ secrets.TOKEN_API_BASE_URL }}
STATIC_API_BASE_URL: ${{ secrets.STATIC_API_BASE_URL }}
SECURITY_ALERTS_API_BASE_URL: ${{ secrets.SECURITY_ALERTS_API_BASE_URL }}
NFT_API_BASE_URL: ${{ secrets.NFT_API_BASE_URL }}

sonarcloud:
permissions:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/publish-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ on:
required: true
SECURITY_ALERTS_API_BASE_URL:
required: true
NFT_API_BASE_URL:
required: true
EXPLORER_BASE_URL:
required: true
jobs:
Expand Down Expand Up @@ -69,6 +71,7 @@ jobs:
TOKEN_API_BASE_URL: ${{ secrets.TOKEN_API_BASE_URL }}
STATIC_API_BASE_URL: ${{ secrets.STATIC_API_BASE_URL }}
SECURITY_ALERTS_API_BASE_URL: ${{ secrets.SECURITY_ALERTS_API_BASE_URL }}
NFT_API_BASE_URL: ${{ secrets.NFT_API_BASE_URL }}
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion packages/snap/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,4 @@
"message": "An unknown error occurred."
}
}
}
}
2 changes: 1 addition & 1 deletion packages/snap/locales/el.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,4 @@
"message": "An unknown error occurred."
}
}
}
}
2 changes: 1 addition & 1 deletion packages/snap/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,4 @@
"message": "An unknown error occurred."
}
}
}
}
2 changes: 1 addition & 1 deletion packages/snap/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,4 @@
"message": "An unknown error occurred."
}
}
}
}
2 changes: 1 addition & 1 deletion packages/snap/locales/hi.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,4 @@
"message": "An unknown error occurred."
}
}
}
}
2 changes: 1 addition & 1 deletion packages/snap/locales/id.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,4 @@
"message": "An unknown error occurred."
}
}
}
}
2 changes: 1 addition & 1 deletion packages/snap/locales/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,4 @@
"message": "An unknown error occurred."
}
}
}
}
2 changes: 1 addition & 1 deletion packages/snap/locales/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,4 @@
"message": "An unknown error occurred."
}
}
}
}
2 changes: 1 addition & 1 deletion packages/snap/locales/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,4 @@
"message": "An unknown error occurred."
}
}
}
}
2 changes: 1 addition & 1 deletion packages/snap/locales/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,4 @@
"message": "An unknown error occurred."
}
}
}
}
2 changes: 1 addition & 1 deletion packages/snap/locales/tl.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,4 @@
"message": "An unknown error occurred."
}
}
}
}
2 changes: 1 addition & 1 deletion packages/snap/locales/tr.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,4 @@
"message": "An unknown error occurred."
}
}
}
}
2 changes: 1 addition & 1 deletion packages/snap/locales/vi.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,4 @@
"message": "An unknown error occurred."
}
}
}
}
2 changes: 1 addition & 1 deletion packages/snap/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,4 @@
"message": "An unknown error occurred."
}
}
}
}
1 change: 1 addition & 0 deletions packages/snap/snap.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const environment = {
TOKEN_API_BASE_URL: process.env.TOKEN_API_BASE_URL ?? '',
STATIC_API_BASE_URL: process.env.STATIC_API_BASE_URL ?? '',
SECURITY_ALERTS_API_BASE_URL: process.env.SECURITY_ALERTS_API_BASE_URL ?? '',
NFT_API_BASE_URL: process.env.NFT_API_BASE_URL ?? '',
LOCAL_API_BASE_URL: process.env.LOCAL_API_BASE_URL ?? '',
};

Expand Down
2 changes: 1 addition & 1 deletion packages/snap/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snap-solana-wallet.git"
},
"source": {
"shasum": "60Zn2UOhpoaLT3yQ5V8UJElF7SiGynw9+dQ9lfZICFQ=",
"shasum": "+7X37iftHlIqWFoG3QMA+Cro5+l3gv2VJQdBmuBnU6I=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
154 changes: 154 additions & 0 deletions packages/snap/src/core/clients/nft-api/NftApiClient.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/* eslint-disable @typescript-eslint/naming-convention */
import type { ICache } from '../../caching/ICache';
import { InMemoryCache } from '../../caching/InMemoryCache';
import type { Serializable } from '../../serialization/types';
import type { ConfigProvider } from '../../services/config';
import type { ILogger } from '../../utils/logger';
import { MOCK_NFT_METADATA_RESPONSE_MAPPED } from './mocks/mockNftMetadataResponseMapped';
import { MOCK_NFT_METADATA_RESPONSE_RAW } from './mocks/mockNftMetadataResponseRaw';
import { MOCK_NFTS_LIST_RESPONSE_MAPPED } from './mocks/mockNftsListResponseMapped';
import { MOCK_NFTS_LIST_RESPONSE_RAW } from './mocks/mockNftsListResponseRaw';
import { NftApiClient } from './NftApiClient';

const mockFetch = jest.fn();
const mockLogger = {
info: jest.fn(console.info),
error: jest.fn(console.error),
warn: jest.fn(console.error),
} as unknown as ILogger;
let mockCache: ICache<Serializable>;

describe('NftApiClient', () => {
let client: NftApiClient;
let mockConfigProvider: ConfigProvider;

beforeEach(() => {
jest.clearAllMocks();

mockCache = new InMemoryCache(mockLogger);

mockConfigProvider = {
get: jest.fn().mockReturnValue({
nftApi: {
baseUrl: 'https://some-mock-url.com',
cacheTtlsMilliseconds: {
listAddressSolanaNfts: 0,
getNftMetadata: 0,
},
},
}),
} as unknown as ConfigProvider;

client = new NftApiClient(
mockConfigProvider,
mockCache,
mockFetch,
mockLogger,
);
});

describe('constructor', () => {
it('rejects invalid baseUrl', async () => {
const invalidConfigProvider = {
get: jest.fn().mockReturnValue({
nftApi: {
baseUrl: 'invalid-url',
cacheTtlsMilliseconds: {
listAddressSolanaNfts: 0,
getNftMetadata: 0,
},
},
}),
} as unknown as ConfigProvider;

expect(
() =>
new NftApiClient(
invalidConfigProvider,
mockCache,
mockFetch,
mockLogger,
),
).toThrow('Invalid URL format');
});
});

describe('listAddressSolanaNfts', () => {
it('should correctly map the API response, covering the logic from mapListAddressSolanaNftsResponse.test.ts', async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: jest.fn().mockResolvedValueOnce({
...MOCK_NFTS_LIST_RESPONSE_RAW,
cursor: null,
}),
});

const nfts = await client.listAddressSolanaNfts('some-address');
expect(nfts).toStrictEqual(MOCK_NFTS_LIST_RESPONSE_MAPPED.items);
});

it('should handle pagination', async () => {
const MOCK_NFTS_LIST_RESPONSE_RAW_PAGE_1 = {
...MOCK_NFTS_LIST_RESPONSE_RAW,
cursor: 'some-cursor',
};
const MOCK_NFTS_LIST_RESPONSE_RAW_PAGE_2 = {
...MOCK_NFTS_LIST_RESPONSE_RAW,
cursor: null,
};
mockFetch.mockResolvedValueOnce({
ok: true,
json: jest
.fn()
.mockResolvedValueOnce(MOCK_NFTS_LIST_RESPONSE_RAW_PAGE_1),
});
mockFetch.mockResolvedValueOnce({
ok: true,
json: jest
.fn()
.mockResolvedValueOnce(MOCK_NFTS_LIST_RESPONSE_RAW_PAGE_2),
});
const nfts = await client.listAddressSolanaNfts('some-address');
expect(nfts).toStrictEqual([
...MOCK_NFTS_LIST_RESPONSE_MAPPED.items,
...MOCK_NFTS_LIST_RESPONSE_MAPPED.items,
]);
expect(mockFetch).toHaveBeenCalledTimes(2);
});
});

describe('getNftMetadata', () => {
it('should fetch and parse solana nft metadata for a given token address', async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: jest.fn().mockResolvedValueOnce(MOCK_NFT_METADATA_RESPONSE_RAW),
});
const nft = await client.getNftMetadata('some-token-address');
expect(nft).toStrictEqual(MOCK_NFT_METADATA_RESPONSE_MAPPED);
});

it('should return null if the fetch fails', async () => {
mockFetch.mockRejectedValueOnce(new Error('some-error'));
const nft = await client.getNftMetadata('some-token-address');
expect(nft).toBeNull();
});
});

describe('getNftsMetadata', () => {
it('should fetch and parse solana nft metadata for a given array of token addresses', async () => {
mockFetch.mockResolvedValue({
ok: true,
json: jest.fn().mockResolvedValue(MOCK_NFT_METADATA_RESPONSE_RAW),
});
const nfts = await client.getNftsMetadata([
'some-token-address-1',
'some-token-address-2',
]);
expect(nfts).toStrictEqual([
MOCK_NFT_METADATA_RESPONSE_MAPPED,
MOCK_NFT_METADATA_RESPONSE_MAPPED,
]);
expect(mockFetch).toHaveBeenCalledTimes(2);
});
});
});
Loading
Loading