Hi wrote this function that takes an url and send back metadata of the page scraped with metascraper
import * as functions from "firebase-functions";
import metascraper from "metascraper";
import metascraperTitle from "metascraper-title";
import metascraperDescription from "metascraper-description";
export const getMetadata = functions.https.onCall(async (data, context) => {
try {
const url = data.url;
const res = await fetch(url);
const html = await res.text();
const metadata = await metascraper([
metascraperTitle(),
metascraperDescription(),
])({html, url});
return {
title: metadata.title,
description: metadata.description,
};
} catch (error) {
functions.logger.error(error);
}
return false;
});
I wrote this test to test this callable function:
import {describe , it, expect} from "vitest"
import { getMetadata } from "./getMetadata";
describe('getMetadata', () => {
it('should return metadata for a given URL', async () => {
const data= { 'url': 'https://example.com' };
const context = { };
const result = await getMetadata(data, context);
expect(result).toEqual({ title: 'Example Domain', description: null });
});
});
Here's the error I get
FAIL src/getMetadata.test.ts > getMetadata > should return metadata for a given URL
TypeError: res.on is not a function
❯ node_modules/firebase-functions/lib/common/providers/https.js:392:17
❯ Module.<anonymous> node_modules/firebase-functions/lib/common/providers/https.js:391:16
❯ src/getMetadata.test.ts:10:26
8| const context = { };
9|
10| const result = await getMetadata(data, context);
| ^
11|
12| expect(result).toEqual({ title: 'Example Domain', description: null });
Can someone please help I don't understand the error, how to fix it?
Use the firebase-functions-test package to test your onCall
functions. The short explanation is that you will use that package to wrap your original function and then you call the wrapped function instead.
Here's a modified example of your function:
import * as functions from "firebase-functions";
export const getMetadata = functions.https.onCall(async (data, context) => {
try {
const url = data.url;
const res = await fetch(url);
const html = await res.text();
return {
url,
html
};
} catch (error) {
functions.logger.error(error);
}
return false;
});
And here's a test that will pass successfully:
import { describe , it, expect } from "vitest";
import { getMetadata } from "./getMetadata";
import firebaseFunctionsTest from "firebase-functions-test";
// Extracting `wrap` out of the lazy-loaded features
const { wrap } = firebaseFunctionsTest();
describe('getMetadata', () => {
it('should return metadata for a given URL', async () => {
// Wrap your function here and then call your wrapped function
const wrappedFirebaseFunction = wrap(getMetadata);
const data = { url: 'https://example.com' };
const result = await wrappedFirebaseFunction(data);
expect(result.url).toEqual('https://example.com');
});
});
The output:
vitest run index.test.js
RUN v0.31.0 /Users/foo/temp
✓ index.test.js (1)
Test Files 1 passed (1)
Tests 1 passed (1)
Start at 10:36:23
Duration 703ms (transform 21ms, setup 0ms, collect 223ms, tests 67ms, environment 0ms, prepare 64ms)
You can read more about unit testing functions at Unit testing of Cloud Functions.