Skip to content

Commit

Permalink
test: add test for merging global fs breadcrumbs
Browse files Browse the repository at this point in the history
  • Loading branch information
DavieReid committed Sep 22, 2023
1 parent 0eca1d6 commit 8e76679
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 38 deletions.
58 changes: 30 additions & 28 deletions packages/plugins/src/BreadcrumbsPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,36 +83,38 @@ const BreadcrumbsPlugin: PluginType<BreadcrumbsPluginPage, BreadcrumbsPluginOpti
// the root breadcrumb is the first breadcrumb for all pages in a source. It is essentially the "first" page in a source
const rootBreadcrumb = breadcrumbs?.[0] || undefined;

let parentDir = path.posix.join(path.posix.dirname(rootBreadcrumb.id), '../');

while (parentDir !== '/') {
const parentDirIndex = path.posix.join(parentDir, options.indexPageName);

// check for this file in the global fs so we have a holistic view of all site pages
if (await globalFilesystem.promises.exists(parentDirIndex)) {
const { breadcrumbs: parentDirBreadcrumbs } = await serialiser.deserialise(
rootBreadcrumb.id,
await globalFilesystem.promises.readFile(parentDirIndex)
);
updatedBreadcrumbs = parentDirBreadcrumbs;
break;
if (rootBreadcrumb) {
let parentDir = path.posix.join(path.posix.dirname(rootBreadcrumb.id), '../');

while (parentDir !== '/') {
const parentDirIndex = path.posix.join(parentDir, options.indexPageName);

// check for this file in the global fs so we have a holistic view of all site pages
if (await globalFilesystem.promises.exists(parentDirIndex)) {
const { breadcrumbs: parentDirBreadcrumbs } = await serialiser.deserialise(
rootBreadcrumb.id,
await globalFilesystem.promises.readFile(parentDirIndex)
);
updatedBreadcrumbs = parentDirBreadcrumbs;
break;
}
parentDir = path.posix.join(path.posix.dirname(parentDirIndex), '../');
}
parentDir = path.posix.join(path.posix.dirname(parentDirIndex), '../');
}

if (updatedBreadcrumbs.length > 0) {
for (const pagePath of pages) {
const page = await serialiser.deserialise(
pagePath,
await mutableFilesystem.promises.readFile(pagePath)
);

// append the parent breadcrumbs **before** the current breadcrumbs
page.breadcrumbs = [...updatedBreadcrumbs, ...page.breadcrumbs];
await mutableFilesystem.promises.writeFile(
pagePath,
await serialiser.serialise(pagePath, page)
);
if (updatedBreadcrumbs.length > 0) {
for (const pagePath of pages) {
const page = await serialiser.deserialise(
pagePath,
await mutableFilesystem.promises.readFile(pagePath)
);

// append the parent breadcrumbs **before** the current breadcrumbs
page.breadcrumbs = [...updatedBreadcrumbs, ...page.breadcrumbs];
await mutableFilesystem.promises.writeFile(
pagePath,
await serialiser.serialise(pagePath, page)
);
}
}
}
}
Expand Down
136 changes: 126 additions & 10 deletions packages/plugins/src/__tests__/BreadcrumbsPlugin.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { serialize } from 'v8';
import BreadcrumbsPlugin, { BreadcrumbsPluginPage } from '../BreadcrumbsPlugin';

const pages: BreadcrumbsPluginPage[] = [
Expand Down Expand Up @@ -57,23 +58,76 @@ const pages: BreadcrumbsPluginPage[] = [
}
];

const mutableFsPages = [
{
fullPath: '/FolderA/SubfolderA/SubfolderB/index.mdx',
route: 'route/folderA/subfolderA/SubfolderB/index',
title: 'Subfolder A Subfolder B Index',
layout: 'DetailOverview',
breadcrumbs: [
{
label: 'Subfolder B Index',
path: 'route/folderA/subfolderA/SubfolderB/index',
id: '/FolderA/SubfolderA/SubfolderB/index.mdx'
}
]
}
];

let writeFileMock = jest.fn();
const volume = {
promises: {
exists: jest.fn(),
glob: jest.fn().mockResolvedValue(mutableFsPages.map(page => page.fullPath)),
mkdir: jest.fn(),
readdir: jest.fn(),
readFile: jest.fn(value =>
Promise.resolve(mutableFsPages.find(page => page.fullPath === value))
),
realpath: jest.fn(),
stat: jest.fn(),
symlink: jest.fn(),
unlink: jest.fn(),
writeFile: writeFileMock
}
};
const globalVolume = {
promises: {
exists: jest.fn().mockResolvedValue(true),
glob: jest.fn().mockResolvedValue(pages.map(page => page.fullPath)),
mkdir: jest.fn(),
readdir: jest.fn(),
readFile: jest.fn(value =>
Promise.resolve(mutableFsPages.find(page => page.fullPath === value))
),
realpath: jest.fn(),
stat: jest.fn(),
symlink: jest.fn(),
unlink: jest.fn(),
writeFile: writeFileMock
}
};

describe('GIVEN the BreadcrumbsPlugin', () => {
let updatedPages: BreadcrumbsPluginPage[] = [];
beforeEach(async () => {
const $afterSource = BreadcrumbsPlugin.$afterSource;
updatedPages =
(await $afterSource?.(
pages,
{ ignorePages: ['sidebar.json'], pageExtensions: ['.mdx'] },
{ indexPageName: 'index.mdx' }
)) || [];
test('THEN it should use the `$afterSource` lifecycle event', () => {
expect(BreadcrumbsPlugin).toHaveProperty('$afterSource');
});

test('THEN it should use the `$afterSource` lifecycle event', () => {
test('THEN it should use the `afterUpdate` lifecycle event', () => {
expect(BreadcrumbsPlugin).toHaveProperty('afterUpdate');
});

describe('AND WHEN `$afterSource` is called', () => {
let updatedPages: BreadcrumbsPluginPage[] = [];
beforeEach(async () => {
const $afterSource = BreadcrumbsPlugin.$afterSource;
updatedPages =
(await $afterSource?.(
pages,
{ ignorePages: ['sidebar.json'], pageExtensions: ['.mdx'] },
{ indexPageName: 'index.mdx' }
)) || [];
});
test('THEN breadcrumbs are added', async () => {
const breadcrumbs = (updatedPages && updatedPages[4].breadcrumbs) || [];

Expand Down Expand Up @@ -112,4 +166,66 @@ describe('GIVEN the BreadcrumbsPlugin', () => {
});
});
});

/**
* This test requires a bit of setup and understanding
*
* The goal is for there to be a file in a mutable filesystem that
* needs breadcrumbs from the global filesystem.
*
* To facilitate this the mutable fs has 1 page which should get the breadcrumbs from the 4th page in the global fs
*
* deserialise will be called 3 times by this plugin event so we use mockReturnValueOnce 3 times
* 1. to read the page from the mutable fs
* 2. to read the 4th page from the global fs
* 3. to read the page from the mutable fs again
*
*/

describe('AND WHEN `afterUpdate` is called', () => {
let serialiseMock = jest.fn();
beforeEach(async () => {
const afterUpdate = BreadcrumbsPlugin.afterUpdate;

(await afterUpdate?.(
volume,
{
globalFilesystem: globalVolume,
ignorePages: ['sidebar.json'],
pageExtensions: ['.mdx'],
serialiser: {
deserialise: jest
.fn()
.mockResolvedValueOnce(mutableFsPages[0])
.mockResolvedValueOnce(pages[3])
.mockResolvedValueOnce(mutableFsPages[0]),
serialise: serialiseMock
}
},
{ indexPageName: 'index.mdx' }
)) || [];
});
test('THEN breadcrumbs from global fs are added', async () => {
expect(writeFileMock).toBeCalledTimes(1);
expect(serialiseMock).toBeCalledTimes(1);
expect(serialiseMock.mock.calls[0][0]).toEqual('/FolderA/SubfolderA/SubfolderB/index.mdx');
expect(serialiseMock.mock.calls[0][1].breadcrumbs).toEqual([
{
label: 'Folder A Index',
path: 'route/folderA/index',
id: '/FolderA/index.mdx'
},
{
label: 'Subfolder A Index',
path: 'route/folderA/subfolderA/index',
id: '/FolderA/SubfolderA/index.mdx'
},
{
label: 'Subfolder B Index',
path: 'route/folderA/subfolderA/SubfolderB/index',
id: '/FolderA/SubfolderA/SubfolderB/index.mdx'
}
]);
});
});
});

1 comment on commit 8e76679

@vercel
Copy link

@vercel vercel bot commented on 8e76679 Sep 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

mosaic – ./

mosaic-mosaic-dev-team.vercel.app
mosaic-git-main-mosaic-dev-team.vercel.app

Please sign in to comment.