import nock from 'nock'; import { beforeEach, describe, expect, it } from 'vitest'; import { RobotsTxtFile } from '../src/internals/robots'; describe('RobotsTxtFile', () => { beforeEach(() => { nock.disableNetConnect(); nock('http://not-exists.com') .persist() .get('/robots.txt') .delay(500) .reply( 200, [ 'User-agent: *', 'Disallow: *deny_all/', 'crawl-delay: 10', 'User-agent: Googlebot', 'Disallow: *deny_googlebot/', 'crawl-delay: 1', 'user-agent: Mozilla', 'crawl-delay: 2', 'sitemap: http://not-exists.com/sitemap_1.xml', 'sitemap: http://not-exists.com/sitemap_2.xml', ].join('\n'), ) .get('*') .reply(404); }); afterEach(() => { nock.cleanAll(); nock.enableNetConnect(); }); it('generates the correct robots.txt URL', async () => { const robots = await RobotsTxtFile.find('http://not-exists.com/nested/index.html'); expect(robots.getSitemaps()).not.toHaveLength(0); }); it('parses allow/deny directives from robots.txt', async () => { const robots = await RobotsTxtFile.find('http://not-exists.com/robots.txt'); console.log(robots.isAllowed('https://crawlee.dev')); expect(robots.isAllowed('http://not-exists.com/something/page.html')).toBe(true); expect(robots.isAllowed('http://not-exists.com/deny_googlebot/page.html')).toBe(true); expect(robots.isAllowed('http://not-exists.com/deny_all/page.html')).toBe(false); }); it('extracts sitemap urls', async () => { const robots = await RobotsTxtFile.find('http://not-exists.com/robots.txt'); expect(robots.getSitemaps()).toEqual([ 'http://not-exists.com/sitemap_1.xml', 'http://not-exists.com/sitemap_2.xml', ]); }); it('respects user-set timeout', async () => { const start = +Date.now(); const robots = RobotsTxtFile.find('http://not-exists.com/robots.txt', undefined, { timeoutMillis: 200 }); await expect(robots).rejects.toThrow(/timeout/i); const end = +Date.now(); expect(end - start).toBeGreaterThanOrEqual(200); expect(end - start).toBeLessThanOrEqual(500); }); it('respects AbortSignal parameter', async () => { const controller = new AbortController(); setTimeout(() => controller.abort(), 200); const start = +Date.now(); const robots = RobotsTxtFile.find('http://not-exists.com/robots.txt', undefined, { signal: controller.signal }); await expect(robots).rejects.toThrow(/aborted/i); const end = +Date.now(); expect(end - start).toBeGreaterThanOrEqual(200); expect(end - start).toBeLessThanOrEqual(500); }); it('respects AbortSignal parameter and timeout together', async () => { const controller = new AbortController(); const start = +Date.now(); const robots = RobotsTxtFile.find('http://not-exists.com/robots.txt', undefined, { signal: controller.signal, timeoutMillis: 200, }); await expect(robots).rejects.toThrow(/timeout/i); const end = +Date.now(); expect(end - start).toBeGreaterThanOrEqual(200); expect(end - start).toBeLessThanOrEqual(500); }); it('parses allow/deny directives from explicitly provided robots.txt contents', async () => { const contents = `User-agent: *', Disallow: *deny_all/ crawl-delay: 10 User-agent: Googlebot Disallow: *deny_googlebot/`; const robots = RobotsTxtFile.from('http://not-exists.com/robots.txt', contents); expect(robots.isAllowed('http://not-exists.com/something/page.html')).toBe(true); expect(robots.isAllowed('http://not-exists.com/deny_googlebot/page.html')).toBe(true); expect(robots.isAllowed('http://not-exists.com/deny_googlebot/page.html', 'Googlebot')).toBe(false); expect(robots.isAllowed('http://not-exists.com/deny_all/page.html')).toBe(true); }); });