/** * 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 path from 'path'; import { type AuthorsMapInput, checkAuthorsMapPermalinkCollisions, getAuthorsMap, validateAuthorsMap, validateAuthorsMapInput, } from '../authorsMap'; import type {AuthorsMap} from '@docusaurus/plugin-content-blog'; describe('checkAuthorsMapPermalinkCollisions', () => { it('do not throw when permalinks are unique', () => { const authors: AuthorsMap = { author1: { name: 'author1', key: 'author1', page: { permalink: '/author1', }, }, author2: { name: 'author2', key: 'author2', page: { permalink: '/author2', }, }, }; expect(() => { checkAuthorsMapPermalinkCollisions(authors); }).not.toThrow(); }); it('throw when permalinks collide', () => { const authors: AuthorsMap = { author1: { name: 'author1', key: 'author1', page: { permalink: '/author1', }, }, author2: { name: 'author1', key: 'author1', page: { permalink: '/author1', }, }, }; expect(() => { checkAuthorsMapPermalinkCollisions(authors); }).toThrowErrorMatchingInlineSnapshot(` "The following permalinks are duplicated: Permalink: /author1 Authors: author1, author1" `); }); }); describe('getAuthorsMap', () => { const fixturesDir = path.join(__dirname, '__fixtures__/authorsMapFiles'); const contentPaths = { contentPathLocalized: fixturesDir, contentPath: fixturesDir, }; it('getAuthorsMap can read yml file', async () => { await expect( getAuthorsMap({ contentPaths, authorsMapPath: 'authors.yml', authorsBaseRoutePath: '/authors', }), ).resolves.toBeDefined(); }); it('getAuthorsMap can read json file', async () => { await expect( getAuthorsMap({ contentPaths, authorsMapPath: 'authors.json', authorsBaseRoutePath: '/authors', }), ).resolves.toBeDefined(); }); it('getAuthorsMap can return undefined if yaml file not found', async () => { await expect( getAuthorsMap({ contentPaths, authorsMapPath: 'authors_does_not_exist.yml', authorsBaseRoutePath: '/authors', }), ).resolves.toBeUndefined(); }); }); describe('validateAuthorsMapInput', () => { it('accept valid authors map', () => { const authorsMap: AuthorsMapInput = { slorber: { name: 'Sébastien Lorber', title: 'maintainer', url: 'https://sebastienlorber.com', imageURL: 'https://github.com/slorber.png', key: 'slorber', page: false, }, yangshun: { name: 'Yangshun Tay', imageURL: 'https://github.com/yangshun.png', randomField: 42, key: 'yangshun', page: false, }, jmarcey: { name: 'Joel', title: 'creator of Docusaurus', hello: new Date(), key: 'jmarcey', page: false, }, }; expect(validateAuthorsMapInput(authorsMap)).toEqual(authorsMap); }); it('rename snake case image_url to camelCase imageURL', () => { const authorsMap: AuthorsMapInput = { slorber: { name: 'Sébastien Lorber', image_url: 'https://github.com/slorber.png', key: 'slorber', page: false, }, }; expect(validateAuthorsMapInput(authorsMap)).toEqual({ slorber: { name: 'Sébastien Lorber', imageURL: 'https://github.com/slorber.png', page: false, key: 'slorber', }, }); }); it('accept author with only image', () => { const authorsMap: AuthorsMapInput = { slorber: { imageURL: 'https://github.com/slorber.png', url: 'https://github.com/slorber', key: 'slorber', page: false, }, }; expect(validateAuthorsMapInput(authorsMap)).toEqual(authorsMap); }); it('reject author without name or image', () => { const authorsMap: AuthorsMapInput = { slorber: { title: 'foo', key: 'slorber', page: false, }, }; expect(() => validateAuthorsMapInput(authorsMap), ).toThrowErrorMatchingInlineSnapshot( `""slorber" must contain at least one of [name, imageURL]"`, ); }); it('reject undefined author', () => { expect(() => validateAuthorsMapInput({ slorber: undefined, }), ).toThrowErrorMatchingInlineSnapshot( `""slorber" cannot be undefined. It should be an author object containing properties like name, title, and imageURL."`, ); }); it('reject null author', () => { expect(() => validateAuthorsMapInput({ slorber: null, }), ).toThrowErrorMatchingInlineSnapshot( `""slorber" should be an author object containing properties like name, title, and imageURL."`, ); }); it('reject array author', () => { expect(() => validateAuthorsMapInput({slorber: []}), ).toThrowErrorMatchingInlineSnapshot( `""slorber" should be an author object containing properties like name, title, and imageURL."`, ); }); it('reject array content', () => { expect(() => validateAuthorsMapInput([]), ).toThrowErrorMatchingInlineSnapshot( `"The authors map file should contain an object where each entry contains an author key and the corresponding author's data."`, ); }); it('reject flat author', () => { expect(() => validateAuthorsMapInput({name: 'Sébastien'}), ).toThrowErrorMatchingInlineSnapshot( `""name" should be an author object containing properties like name, title, and imageURL."`, ); }); it('reject non-map author', () => { const authorsMap: AuthorsMapInput = { // @ts-expect-error: intentionally invalid slorber: [], }; expect(() => validateAuthorsMapInput(authorsMap), ).toThrowErrorMatchingInlineSnapshot( `""slorber" should be an author object containing properties like name, title, and imageURL."`, ); }); }); describe('authors socials', () => { it('valid known author map socials', () => { const authorsMap: AuthorsMapInput = { ozaki: { name: 'ozaki', socials: { twitter: 'ozakione', github: 'ozakione', }, key: 'ozaki', page: false, }, }; expect(validateAuthorsMap(authorsMap)).toEqual(authorsMap); }); it('throw socials that are not strings', () => { const authorsMap: AuthorsMapInput = { ozaki: { name: 'ozaki', socials: { // @ts-expect-error: for tests twitter: 42, }, }, }; expect(() => validateAuthorsMap(authorsMap), ).toThrowErrorMatchingInlineSnapshot( `""ozaki.socials.twitter" must be a string"`, ); }); it('throw socials that are objects', () => { const authorsMap: AuthorsMapInput = { ozaki: { name: 'ozaki', socials: { // @ts-expect-error: for tests twitter: {link: 'ozakione'}, }, }, }; expect(() => validateAuthorsMap(authorsMap), ).toThrowErrorMatchingInlineSnapshot( `""ozaki.socials.twitter" must be a string"`, ); }); it('valid unknown author map socials', () => { const authorsMap: AuthorsMapInput = { ozaki: { name: 'ozaki', socials: { random: 'ozakione', }, key: 'ozaki', page: false, }, }; expect(validateAuthorsMap(authorsMap)).toEqual(authorsMap); }); });