Skip to content

Instantly share code, notes, and snippets.

@YonatanKra
Last active December 17, 2024 06:22
Show Gist options
  • Save YonatanKra/2bd26b9005d6eb1a099461a414e4ae32 to your computer and use it in GitHub Desktop.
Save YonatanKra/2bd26b9005d6eb1a099461a414e4ae32 to your computer and use it in GitHub Desktop.
import { AltTextBot } from './find-altless-posts.js';
let mockAtpAgent;
const resolvedHandle = {
did: 'handle-did'
};
const resetAtpAgentMock = () => {
mockAtpAgent = {
getPost: vi.fn(),
resolveHandle: vi.fn().mockResolvedValue({
data: resolvedHandle
}),
login: vi.fn()
};
}
vi.mock('@atproto/api', () => ({
AtpAgent: vi.fn(() => mockAtpAgent),
}));
describe('AltTextBot', () => {
const postUri = 'postUri';
let bot: AltTextBot;
beforeEach(async () => {
resetAtpAgentMock();
bot = new AltTextBot();
});
it('should initialize a new instance', async () => {
expect(bot).toBeDefined();
});
describe('checkSinglePost()', () => {
it('should return the error message if fetch post failed', async () => {
const error = { message: 'error' };
mockAtpAgent.getPost.mockRejectedValue(error);
const result = await bot.checkSinglePost(postUri);
expect(result).toEqual(error);
});
it('should get the post using atpAgent', async () => {
const postUri = 'https://bsky.app/profile/yonatankra.com/post/3lczalvz7uk2l';
mockAtpAgent.getPost.mockResolvedValueOnce(postUri);
await bot.checkSinglePost(postUri);
expect(mockAtpAgent.getPost).toHaveBeenCalledWith({
"collection": "app.bsky.feed.post",
"repo": "handle-did",
"rkey": "3lczalvz7uk2l",
});
expect(mockAtpAgent.getPost).toHaveBeenCalledTimes(1);
});
it('should return the post with altLess images list', async () => {
const imageWithoutAlt = { alt: '' };
const imageWithAlt = { alt: 'I have Alt text!' };
const post = {
uri: 'postUri',
cid: 'postCid',
value: {
embed: {
images: [imageWithoutAlt, imageWithAlt, imageWithoutAlt],
$type: 'image'
},
text: '',
createdAt: ''
},
};
mockAtpAgent.getPost.mockResolvedValueOnce(post);
const result = await bot.checkSinglePost(postUri);
expect(result).toEqual({ post, imagesWithoutAlt: [imageWithoutAlt, imageWithoutAlt] })
});
});
describe('login', () => {
it('should login using AtProto SDK', async () => {
const handle = 'testUser';
const password = 'testPassword';
await bot.login(handle, password);
expect(mockAtpAgent.login).toHaveBeenCalledWith({
identifier: handle,
password: password,
});
});
});
});
import { AtpAgent } from "@atproto/api";
import { Record } from "@atproto/api/dist/client/types/app/bsky/feed/post";
export class AltTextBot {
#agent: AtpAgent = new AtpAgent({ service: 'https://bsky.social' });
#returnPostWithAltlessImages(post: { uri: string; cid: string; value: Record; }) {
const images = post.value?.embed?.images || [];
const imagesWithoutAlt = images.filter(img => !img.alt);
return { post, imagesWithoutAlt };
}
async checkSinglePost(postUri: string) {
try {
const post = await this.#agent.getPost(await parsePostUri(postUri, this.#agent));
return this.#returnPostWithAltlessImages(post);
} catch (e) {
return e;
}
}
async login(handle: string, password: string): Promise<void> {
await this.#agent.login({
identifier: handle,
password: password
});
}
}
async function parsePostUri(uri: string, agent: AtpAgent): Promise<{ repo: string; collection: string; rkey: string; }> {
// Extract handle and post ID
const match = uri.match(/profile\/([^/]+)\/post\/([^/]+)/);
if (!match) {
return {
repo: '',
collection: '',
rkey: '',
};
}
const [, handle, rkey] = match;
const { data: { did: repo } } = await agent.resolveHandle({ handle });
const collection = 'app.bsky.feed.post';
return {
repo,
collection,
rkey
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment