Skip to content
Open
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
16 changes: 12 additions & 4 deletions src/utils/actor_card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ export const DEFAULT_CARD_OPTIONS: ActorCardOptions = {
includeMetadata: true,
};

function normalizeBlankSpaces(value?: string | null): string {
return value?.replaceAll(/\s+/g, ' ').trim() ?? '';
}

/**
* Private intermediate representation holding all extracted actor data.
* Preserves raw PricingInfo so both markdown (pricingInfoToString) and
Expand Down Expand Up @@ -87,14 +91,16 @@ function extractActorData(
): ExtractedActorData {
const actorFullName = `${actor.username}/${actor.name}`;
const actorUrl = `${APIFY_STORE_URL}/${actorFullName}`;
const normalizedTitle = normalizeBlankSpaces(actor.title);
const normalizedDescription = normalizeBlankSpaces(actor.description);

const data: ExtractedActorData = {
actorFullName,
actorUrl,
title: actor.title,
title: normalizedTitle || undefined,
pictureUrl: actor.pictureUrl || undefined,
description: options.includeDescription
? (actor.description || 'No description provided.')
? (normalizedDescription || 'No description provided.')
: '',
pricingInfo: options.includePricing ? getActorPricingInfo(actor) : null,
developer: { username: '', isOfficialApify: false, url: '' },
Expand Down Expand Up @@ -285,13 +291,15 @@ export function formatActorForWidget(
userTier: PricingTier,
): WidgetActor {
const fullName = `${actor.username}/${actor.name}`;
const normalizedTitle = normalizeBlankSpaces(actor.title);
const normalizedDescription = normalizeBlankSpaces(actor.description);
return {
id: actor.id,
name: actor.name,
username: actor.username,
fullName,
title: actor.title || actor.name,
description: actor.description || 'No description available',
title: normalizedTitle || actor.name,
description: normalizedDescription || 'No description available',
pictureUrl: actor.pictureUrl || '',
stats: {
actorReviewRating: ('actorReviewRating' in actor && actor.actorReviewRating)
Expand Down
34 changes: 33 additions & 1 deletion tests/unit/utils.actor_card.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Actor } from 'apify-client';
import { describe, expect, it } from 'vitest';

import type { ActorStoreList } from '../../src/types.js';
import { formatActorToActorCard, formatActorToStructuredCard } from '../../src/utils/actor_card.js';
import { formatActorForWidget, formatActorToActorCard, formatActorToStructuredCard } from '../../src/utils/actor_card.js';

// Mock Actor data for testing (based on real apify/rag-web-browser Actor)
const mockActor: Actor = {
Expand Down Expand Up @@ -83,6 +83,13 @@ const mockDeprecatedActor: Actor = {
isDeprecated: true,
} as unknown as Actor;

const mockActorWithIrregularSpaces: ActorStoreList = {
...mockActorStoreList,
id: 'actor-spaces',
title: ' Store Actor \n Deluxe ',
description: 'A store listing actor\nfor\t testing ',
} as unknown as ActorStoreList;

describe('formatActorToActorCard', () => {
describe('backwards compatibility (no options)', () => {
it('should include all sections when no options are provided', () => {
Expand Down Expand Up @@ -126,6 +133,15 @@ describe('formatActorToActorCard', () => {
const result = formatActorToActorCard(mockActorStoreList);
expect(result).toContain('- **Categories:** Web Scraping, AI');
});

it('should normalize irregular whitespace in titles and descriptions', () => {
const result = formatActorToActorCard(mockActorWithIrregularSpaces);

expect(result).toContain('## [Store Actor Deluxe](https://apify.com/community/store-actor)');
expect(result).toContain('- **Description:** A store listing actor for testing');
expect(result).not.toContain(' ');
expect(result).not.toContain('\t');
});
});

describe('granular options - includeDescription', () => {
Expand Down Expand Up @@ -375,6 +391,13 @@ describe('formatActorToStructuredCard', () => {
const result = formatActorToStructuredCard(mockActorStoreList);
expect(result.rating).toBeDefined();
});

it('should normalize irregular whitespace in structured output', () => {
const result = formatActorToStructuredCard(mockActorWithIrregularSpaces);

expect(result.title).toBe('Store Actor Deluxe');
expect(result.description).toBe('A store listing actor for testing');
});
});

describe('granular options - includeDescription', () => {
Expand Down Expand Up @@ -574,3 +597,12 @@ describe('formatActorToStructuredCard', () => {
});
});
});

describe('formatActorForWidget', () => {
it('should normalize irregular whitespace in widget output', () => {
const result = formatActorForWidget(mockActorWithIrregularSpaces, 'FREE');

expect(result.title).toBe('Store Actor Deluxe');
expect(result.description).toBe('A store listing actor for testing');
});
});
Loading