From 73d3e4801af42a7784d2c9972cf0daa85be5e21c Mon Sep 17 00:00:00 2001 From: Shreedhar Bhat Date: Mon, 21 Apr 2025 10:30:53 +0530 Subject: [PATCH] test(reading-time): Unit tests for calculating reading time --- .../src/__tests__/readingTime.test.ts | 56 +++++++++++++++++++ .../src/blogUtils.ts | 4 +- .../src/readingTime.ts | 27 +++++++++ 3 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 packages/docusaurus-plugin-content-blog/src/__tests__/readingTime.test.ts create mode 100644 packages/docusaurus-plugin-content-blog/src/readingTime.ts diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/readingTime.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/readingTime.test.ts new file mode 100644 index 0000000000..d48d6dffda --- /dev/null +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/readingTime.test.ts @@ -0,0 +1,56 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {calculateReadingTime} from '../readingTime'; + +describe('calculateReadingTime', () => { + it('calculates reading time for empty content', () => { + expect(calculateReadingTime('')).toBe(0); + }); + + it('calculates reading time for short content', () => { + const content = 'This is a short test content.'; + expect(calculateReadingTime(content)).toBe(0.02); + }); + + it('calculates reading time for long content', () => { + const content = 'This is a test content. '.repeat(100); + expect(calculateReadingTime(content)).toBe(1.6666666666666667); + }); + + it('respects custom words per minute', () => { + const content = 'This is a test content. '.repeat(100); + expect(calculateReadingTime(content, {wordsPerMinute: 100})).toBe(5); + }); + + it('handles content with special characters', () => { + const content = 'Hello! How are you? This is a test...'; + expect(calculateReadingTime(content)).toBe(0.02666666666666667); + }); + + it('handles content with multiple lines', () => { + const content = `This is line 1. + This is line 2. + This is line 3.`; + expect(calculateReadingTime(content)).toBe(0.04); + }); + + it('handles content with HTML tags', () => { + const content = '

This is a test content.

'; + expect(calculateReadingTime(content)).toBe(0.016666666666666666); + }); + + it('handles content with markdown', () => { + const content = '# Title\n\nThis is **bold** and *italic* text.'; + expect(calculateReadingTime(content)).toBe(0.02666666666666667); + }); + + it('handles CJK content', () => { + const content = '你好,世界!这是一段测试内容。'; + expect(calculateReadingTime(content)).toBe(0.04); + }); +}); diff --git a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts index ab7426eac5..2cc84bac76 100644 --- a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts +++ b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts @@ -9,7 +9,6 @@ import fs from 'fs-extra'; import path from 'path'; import _ from 'lodash'; import logger from '@docusaurus/logger'; -import readingTime from 'reading-time'; import { parseMarkdownFile, normalizeUrl, @@ -32,6 +31,7 @@ import {getTagsFile} from '@docusaurus/utils-validation'; import {validateBlogPostFrontMatter} from './frontMatter'; import {getBlogPostAuthors} from './authors'; import {reportAuthorsProblems} from './authorsProblems'; +import {calculateReadingTime} from './readingTime'; import type {TagsFile} from '@docusaurus/utils'; import type {LoadContext, ParseFrontMatter} from '@docusaurus/types'; import type { @@ -211,7 +211,7 @@ async function parseBlogPostMarkdownFile({ } const defaultReadingTime: ReadingTimeFunction = ({content, options}) => - readingTime(content, options).minutes; + calculateReadingTime(content, options); async function processBlogSourceFile( blogSourceRelative: string, diff --git a/packages/docusaurus-plugin-content-blog/src/readingTime.ts b/packages/docusaurus-plugin-content-blog/src/readingTime.ts new file mode 100644 index 0000000000..d263a8c6fb --- /dev/null +++ b/packages/docusaurus-plugin-content-blog/src/readingTime.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import readingTime from 'reading-time'; + +const DEFAULT_WORDS_PER_MINUTE = 300; + +interface ReadingTimeOptions { + wordsPerMinute?: number; + wordBound?: (char: string) => boolean; +} + +/** + * Calculates the reading time for a given content string. + * Uses the reading-time package under the hood. + */ +export function calculateReadingTime( + content: string, + options: ReadingTimeOptions = {}, +): number { + const wordsPerMinute = options.wordsPerMinute ?? DEFAULT_WORDS_PER_MINUTE; + return readingTime(content, {wordsPerMinute}).minutes; +}