Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions packages/integrations/mdx/test/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import type * as estree from 'estree';
import type * as hast from 'hast';
import type * as mdast from 'mdast';
import type * as unified from 'unified';
import {
AstroIntegrationLogger,
type AstroLogMessage,
} from '../../../astro/dist/core/logger/core.js';

export type RemarkPlugin<PluginParameters extends any[] = any[]> = unified.Plugin<
PluginParameters,
Expand All @@ -17,3 +21,24 @@ export type RecmaPlugin<PluginParameters extends any[] = any[]> = unified.Plugin
PluginParameters,
estree.Program
>;

export class SpyIntegrationLogger extends AstroIntegrationLogger {
readonly messages: AstroLogMessage[];

constructor() {
const messages: AstroLogMessage[] = [];
super(
{
destination: {
write(chunk): boolean {
messages.push(chunk);
return true;
},
},
level: 'warn',
},
'test-spy',
);
this.messages = messages;
}
}
10 changes: 7 additions & 3 deletions packages/integrations/mdx/test/units/mdx-compilation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import { rehypeHeadingIds } from '@astrojs/markdown-remark';
import { compile as _compile, type CompileOptions, nodeTypes } from '@mdx-js/mdx';
import type { AstroIntegrationLogger } from 'astro';
import { visit as estreeVisit } from 'estree-util-visit';
import rehypeRaw from 'rehype-raw';
import remarkGfm from 'remark-gfm';
import remarkSmartypants from 'remark-smartypants';
import { visit } from 'unist-util-visit';
import { ignoreStringPlugins } from '../../dist/utils.js';
import type { RecmaPlugin, RehypePlugin, RemarkPlugin } from '../test-utils.js';
import {
SpyIntegrationLogger,
type RecmaPlugin,
type RehypePlugin,
type RemarkPlugin,
} from '../test-utils.ts';

/**
* Compile MDX to JSX string output for inspection.
Expand Down Expand Up @@ -259,7 +263,7 @@ describe('MDX string-based plugin filtering', () => {
// When a string-based plugin is provided, the ignoreStringPlugins
// function filters it out. We test the filter function directly in utils.test.js.
// Here we verify that only function plugins affect output.
const logger = { warn() {} } as unknown as AstroIntegrationLogger;
const logger = new SpyIntegrationLogger();

const plugins = ['remark-toc', () => (tree: unknown) => tree];
const filtered = ignoreStringPlugins(plugins, logger);
Expand Down
31 changes: 11 additions & 20 deletions packages/integrations/mdx/test/units/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import type { AstroConfig, AstroIntegrationLogger } from 'astro';
import type { AstroConfig } from 'astro';
import {
appendForwardSlash,
getFileInfo,
ignoreStringPlugins,
jsToTreeNode,
} from '../../dist/utils.js';
import { SpyIntegrationLogger } from '../test-utils.ts';

describe('utils', () => {
describe('appendForwardSlash', () => {
Expand Down Expand Up @@ -124,62 +125,52 @@ describe('utils', () => {
});

describe('ignoreStringPlugins', () => {
function mockLogger(): AstroIntegrationLogger & { warnings: string[] } {
const warnings: string[] = [];
return {
warn: (msg: string) => {
warnings.push(msg);
},
warnings,
} as AstroIntegrationLogger & { warnings: string[] };
}

it('returns function plugins unchanged', () => {
const plugin1 = () => {};
const plugin2 = () => {};
const logger = mockLogger();
const logger = new SpyIntegrationLogger();
const result = ignoreStringPlugins([plugin1, plugin2], logger);
assert.equal(result.length, 2);
assert.equal(result[0], plugin1);
assert.equal(result[1], plugin2);
assert.equal(logger.warnings.length, 0);
assert.equal(logger.messages.filter((m) => m.level === 'warn').length, 0);
});

it('filters out string-based plugins', () => {
const fnPlugin = () => {};
const logger = mockLogger();
const logger = new SpyIntegrationLogger();
const result = ignoreStringPlugins(['remark-toc', fnPlugin], logger);
assert.equal(result.length, 1);
assert.equal(result[0], fnPlugin);
});

it('filters out array-based string plugins [string, options]', () => {
const fnPlugin = () => {};
const logger = mockLogger();
const logger = new SpyIntegrationLogger();
const result = ignoreStringPlugins([['remark-toc', {}], fnPlugin], logger);
assert.equal(result.length, 1);
assert.equal(result[0], fnPlugin);
});

it('logs warnings for string plugins', () => {
const logger = mockLogger();
const logger = new SpyIntegrationLogger();
ignoreStringPlugins(['remark-toc', ['rehype-highlight', {}]], logger);
// One warning per string plugin + one summary warning
assert.equal(logger.warnings.length, 3);
assert.equal(logger.messages.filter((m) => m.level === 'warn').length, 3);
});

it('returns empty array for all string plugins', () => {
const logger = mockLogger();
const logger = new SpyIntegrationLogger();
const result = ignoreStringPlugins(['remark-toc'], logger);
assert.equal(result.length, 0);
});

it('handles array-based function plugins [function, options]', () => {
const fnPlugin = () => {};
const logger = mockLogger();
const logger = new SpyIntegrationLogger();
const result = ignoreStringPlugins([[fnPlugin, { option: true }]], logger);
assert.equal(result.length, 1);
assert.equal(logger.warnings.length, 0);
assert.equal(logger.messages.filter((m) => m.level === 'warn').length, 0);
});
});
});
Loading