MM-59600 Add unit tests to utils/opengraph (#8444)

* Add unit tests to utils/opengraph

* exporting only for tests

---------

Co-authored-by: Rahim Rahman <rahim.rahman@mattermost.com>
This commit is contained in:
Joram Wilander 2025-01-06 15:30:48 -05:00 committed by GitHub
parent 72ccd763e6
commit 2307985539
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 136 additions and 1 deletions

View file

@ -1,7 +1,19 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {getDistanceBW2Points, getNearestPoint} from './opengraph';
import {getDistanceBW2Points, getNearestPoint, fetchOpenGraph, testExports} from './opengraph';
const {fetchRaw, getFavIcon} = testExports;
let mockedFetch: jest.SpyInstance;
beforeEach(() => {
mockedFetch = jest.spyOn(global, 'fetch');
});
afterEach(() => {
jest.clearAllMocks();
});
describe('Utility Functions', () => {
describe('getDistanceBW2Points', () => {
@ -62,3 +74,121 @@ describe('Utility Functions', () => {
});
});
});
describe('fetchRaw', () => {
it('should fetch raw HTML from a URL', async () => {
const mockResponse = {
ok: true,
text: jest.fn().mockResolvedValue('<html></html>'),
};
mockedFetch.mockResolvedValue(mockResponse as any);
const result = await fetchRaw('http://example.com');
expect(fetch).toHaveBeenCalledWith('http://example.com', {
headers: {
'User-Agent': 'OpenGraph',
'Cache-Control': 'no-cache',
Accept: '*/*',
Connection: 'keep-alive',
},
});
expect(result).toBe('<html></html>');
});
it('should return response if not ok', async () => {
const mockResponse = {
ok: false,
};
mockedFetch.mockResolvedValue(mockResponse as any);
const result = await fetchRaw('http://example.com');
expect(result).toBe(mockResponse);
});
it('should return error message on fetch failure', async () => {
const mockError = new Error('Network error');
mockedFetch.mockRejectedValue(mockError);
const result = await fetchRaw('http://example.com');
expect(result).toEqual({message: 'Network error'});
});
});
describe('getFavIcon', () => {
it('should return the largest favicon URL', () => {
const mockHtml = '<html><head><link rel="icon" href="/favicon-32x32.png" sizes="32x32"><link rel="icon" href="/favicon-16x16.png" sizes="16x16"></head></html>';
const result = getFavIcon('http://example.com', mockHtml);
expect(result).toBe('http://example.com/favicon-32x32.png');
});
it('should return default favicon URL if no icons found', () => {
const mockHtml = '<html><head></head></html>';
const result = getFavIcon('http://example.com', mockHtml);
expect(result).toBe('http://example.com/favicon.ico');
});
it('should handle shortcut icon rel attribute', () => {
const mockHtml = '<html><head><link rel="shortcut icon" href="/favicon.png"></head></html>';
const result = getFavIcon('http://example.com', mockHtml);
expect(result).toBe('http://example.com/favicon.png');
});
it('should handle absolute URLs in href', () => {
const mockHtml = '<html><head><link rel="icon" href="https://cdn.example.com/favicon.png"></head></html>';
const result = getFavIcon('http://example.com', mockHtml);
expect(result).toBe('https://cdn.example.com/favicon.png');
});
it('should handle icons without sizes attribute', () => {
const mockHtml = '<html><head><link rel="icon" href="/favicon.png"><link rel="icon" href="/favicon-32x32.png" sizes="32x32"></head></html>';
const result = getFavIcon('http://example.com', mockHtml);
expect(result).toBe('http://example.com/favicon-32x32.png');
});
});
describe('fetchOpenGraph', () => {
it('should fetch OpenGraph data from a URL', async () => {
const mockHtml = '<html><head><title>Example</title><meta property="og:title" content="OpenGraph Title"><meta property="og:image" content="http://example.com/image.png"></head></html>';
const mockResponse = {
ok: true,
text: jest.fn().mockResolvedValue(mockHtml),
};
mockedFetch.mockResolvedValue(mockResponse as any);
const result = await fetchOpenGraph('http://example.com', true);
expect(result).toEqual({
link: 'http://example.com',
imageURL: 'http://example.com/image.png',
favIcon: 'http://example.com/favicon.ico',
title: 'OpenGraph Title',
});
});
it('should return error if fetchRaw fails', async () => {
const mockError = {message: 'Network error'};
mockedFetch.mockRejectedValue(mockError);
const result = await fetchOpenGraph('http://example.com');
expect(result).toEqual({
link: 'http://example.com',
error: new Error('Network error'),
});
});
it('should return default title if og:title is not found', async () => {
const mockHtml = '<html><head><title>Example</title></head></html>';
const mockResponse = {
ok: true,
text: jest.fn().mockResolvedValue(mockHtml),
};
mockedFetch.mockResolvedValue(mockResponse as any);
const result = await fetchOpenGraph('http://example.com');
expect(result).toEqual({
link: 'http://example.com',
imageURL: null,
favIcon: undefined,
title: 'Example',
});
});
});

View file

@ -188,3 +188,8 @@ export const fetchOpenGraph = async (url: string, includeFavIcon = false): Promi
};
}
};
export const testExports = {
fetchRaw,
getFavIcon,
};