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
2 changes: 1 addition & 1 deletion packages/markdoc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"devDependencies": {
"@astrojs/markdoc": "^1.0.0",
"@astrojs/starlight": "workspace:*",
"vitest": "^4.1.0-beta.6"
"vitest": "^4.1.0"
},
"peerDependencies": {
"@astrojs/markdoc": "^1.0.0",
Expand Down
16 changes: 9 additions & 7 deletions packages/starlight/__tests__/basics/git.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { assert, describe, expect, test } from 'vitest';
import { describe, expect, test, vi } from 'vitest';
import {
getAllNewestCommitDate,
getNewestCommitDate,
Expand Down Expand Up @@ -119,13 +119,13 @@ describe('getAllNewestCommitDate', () => {

for (const [file, date] of latestDates.entries()) {
const expectedDate = expectedDates.get(file);
assert.ok(expectedDate, `Unexpected tracked file: ${file}`);
expect.assert(expectedDate, `Unexpected tracked file: ${file}`);
expectCommitDateToEqual(new Date(date), expectedDate);
}

for (const file of expectedDates.keys()) {
const latestDate = latestDates.get(file);
assert.ok(latestDate, `Missing tracked file: ${file}`);
expect.assert(latestDate, `Missing tracked file: ${file}`);
}
});

Expand All @@ -152,9 +152,11 @@ describe('getAllNewestCommitDate', () => {
});
});

function expectCommitDateToEqual(commitDate: CommitDate, expectedDateStr: ISODate) {
const expectedDate = new Date(expectedDateStr);
expect(commitDate).toStrictEqual(expectedDate);
}
const expectCommitDateToEqual = vi.defineHelper(
(commitDate: CommitDate, expectedDateStr: ISODate) => {
const expectedDate = new Date(expectedDateStr);
expect(commitDate).toStrictEqual(expectedDate);
}
);

type CommitDate = ReturnType<typeof getNewestCommitDate>;
4 changes: 2 additions & 2 deletions packages/starlight/__tests__/basics/i18n.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { assert, describe, expect, test, vi } from 'vitest';
import { describe, expect, test, vi } from 'vitest';
import config from 'virtual:starlight/user-config';
import { processI18nConfig, pickLang } from '../../utils/i18n';
import type { AstroConfig, AstroUserConfig } from 'astro';
Expand All @@ -24,7 +24,7 @@ describe('processI18nConfig', () => {

expect(astroI18nConfig.defaultLocale).toBe('en');
expect(astroI18nConfig.locales).toEqual(['en']);
assert(typeof astroI18nConfig.routing !== 'string');
expect.assert(typeof astroI18nConfig.routing !== 'string');
expect(astroI18nConfig.routing?.prefixDefaultLocale).toBe(false);

// The Starlight configuration should not be modified.
Expand Down
112 changes: 62 additions & 50 deletions packages/starlight/__tests__/basics/translations.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, expect, test, vi } from 'vitest';
import { beforeAll, describe, expect, test, vi } from 'vitest';
import { useTranslations } from '../../utils/translations';
import translations from '../../translations';

Expand All @@ -10,36 +10,40 @@ describe('useTranslations()', () => {
});
});

describe('t()', async () => {
// The mocked user-defined translations are scoped to this `describe` block so that they do not
// affect other tests (`vi.mock` → `vi.doMock`).
vi.doMock('astro:content', async () =>
(await import('../test-utils')).mockedAstroContent({
i18n: [
[
'en',
{
'test.interpolation': '{{subject}} is {{adjective}}',
'test.dataModel': 'Powered by {{integration.name}}',
'test.escape': 'The tag is {{tag}}',
'test.unescape': 'The tag is {{- tag}}',
'test.currency': 'The price is {{price, currency(USD)}}',
'test.list': '{{subjects, list}} are awesome',
'test.count_one': '{{count}} project',
'test.count_other': '{{count}} projects',
'test.nesting1': '$t(test.nesting2) is nested',
'test.nesting2': 'this UI string',
},
describe('t()', () => {
let t: ReturnType<typeof useTranslations>;

beforeAll(async () => {
// The mocked user-defined translations are scoped to this `describe` block so that they do not
// affect other tests (`vi.mock` → `vi.doMock`).
vi.doMock('astro:content', async () =>
(await import('../test-utils')).mockedAstroContent({
i18n: [
[
'en',
{
'test.interpolation': '{{subject}} is {{adjective}}',
'test.dataModel': 'Powered by {{integration.name}}',
'test.escape': 'The tag is {{tag}}',
'test.unescape': 'The tag is {{- tag}}',
'test.currency': 'The price is {{price, currency(USD)}}',
'test.list': '{{subjects, list}} are awesome',
'test.count_one': '{{count}} project',
'test.count_other': '{{count}} projects',
'test.nesting1': '$t(test.nesting2) is nested',
'test.nesting2': 'this UI string',
},
],
],
],
})
);
// Reset the modules registry so that re-importing `../../utils/translations` re-evaluates the
// module and re-computes `useTranslations`. Re-importing the module is necessary because
// top-level imports cannot be re-evaluated.
vi.resetModules();
const { useTranslations } = await import('../../utils/translations');
const t = useTranslations(undefined);
})
);
// Reset the modules registry so that re-importing `../../utils/translations` re-evaluates the
// module and re-computes `useTranslations`. Re-importing the module is necessary because
// top-level imports cannot be re-evaluated.
vi.resetModules();
const { useTranslations } = await import('../../utils/translations');
t = useTranslations(undefined);
});

test('supports using interpolation', () => {
expect(t).toBeTypeOf('function');
Expand Down Expand Up @@ -104,33 +108,41 @@ describe('t()', async () => {
});
});

describe('t.all()', async () => {
// See the `t()` tests for an explanation of how the user-defined translations are mocked.
vi.doMock('astro:content', async () =>
(await import('../test-utils')).mockedAstroContent({
i18n: [['en', { 'test.foo': 'bar' }]],
})
);
vi.resetModules();
const { useTranslations } = await import('../../utils/translations');
const t = useTranslations(undefined);
describe('t.all()', () => {
let t: ReturnType<typeof useTranslations>;

beforeAll(async () => {
// See the `t()` tests for an explanation of how the user-defined translations are mocked.
vi.doMock('astro:content', async () =>
(await import('../test-utils')).mockedAstroContent({
i18n: [['en', { 'test.foo': 'bar' }]],
})
);
vi.resetModules();
const { useTranslations } = await import('../../utils/translations');
t = useTranslations(undefined);
});

test('returns all translations including custom ones', () => {
expect(t.all).toBeTypeOf('function');
expect(t.all()).toEqual({ ...translations.en, 'test.foo': 'bar' });
});
});

describe('t.exists()', async () => {
// See the `t()` tests for an explanation of how the user-defined translations are mocked.
vi.doMock('astro:content', async () =>
(await import('../test-utils')).mockedAstroContent({
i18n: [['en', { 'test.foo': 'bar' }]],
})
);
vi.resetModules();
const { useTranslations } = await import('../../utils/translations');
const t = useTranslations(undefined);
describe('t.exists()', () => {
let t: ReturnType<typeof useTranslations>;

beforeAll(async () => {
// See the `t()` tests for an explanation of how the user-defined translations are mocked.
vi.doMock('astro:content', async () =>
(await import('../test-utils')).mockedAstroContent({
i18n: [['en', { 'test.foo': 'bar' }]],
})
);
vi.resetModules();
const { useTranslations } = await import('../../utils/translations');
t = useTranslations(undefined);
});

test('returns `true` for existing translations', () => {
expect(t.exists).toBeTypeOf('function');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { assert, describe, expect, test } from 'vitest';
import { describe, expect, test } from 'vitest';
import type { AstroConfig } from 'astro';
import config from 'virtual:starlight/user-config';
import { processI18nConfig } from '../../utils/i18n';
Expand All @@ -19,7 +19,7 @@ describe('processI18nConfig', () => {
},
]
`);
assert(typeof astroI18nConfig.routing !== 'string');
expect.assert(typeof astroI18nConfig.routing !== 'string');
expect(astroI18nConfig.routing?.prefixDefaultLocale).toBe(true);

// The Starlight configuration should not be modified.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { assert, describe, expect, test } from 'vitest';
import { describe, expect, test } from 'vitest';
import config from 'virtual:starlight/user-config';
import { processI18nConfig } from '../../utils/i18n';

Expand Down Expand Up @@ -30,7 +30,7 @@ describe('processI18nConfig', () => {
},
]
`);
assert(typeof astroI18nConfig.routing !== 'string');
expect.assert(typeof astroI18nConfig.routing !== 'string');
expect(astroI18nConfig.routing?.prefixDefaultLocale).toBe(false);

// The Starlight configuration should not be modified.
Expand Down
4 changes: 2 additions & 2 deletions packages/starlight/__tests__/i18n-root-locale/i18n.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { assert, describe, expect, test } from 'vitest';
import { describe, expect, test } from 'vitest';
import type { AstroConfig } from 'astro';
import config from 'virtual:starlight/user-config';
import { processI18nConfig } from '../../utils/i18n';
Expand Down Expand Up @@ -30,7 +30,7 @@ describe('processI18nConfig', () => {
},
]
`);
assert(typeof astroI18nConfig.routing !== 'string');
expect.assert(typeof astroI18nConfig.routing !== 'string');
expect(astroI18nConfig.routing?.prefixDefaultLocale).toBe(false);

// The Starlight configuration should not be modified.
Expand Down
7 changes: 5 additions & 2 deletions packages/starlight/__tests__/i18n-root-locale/routing.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getRouteDataTestContext } from '../test-utils';
import config from 'virtual:starlight/user-config';
import { assert, expect, test, vi } from 'vitest';
import { expect, test, vi } from 'vitest';
import { routes } from '../../utils/routing';
import { generateRouteData } from '../../utils/routing/data';
import * as git from 'virtual:starlight/git-info';
Expand Down Expand Up @@ -70,7 +70,10 @@ test('fallback routes use their own locale data', () => {
test('fallback routes use fallback entry last updated dates', () => {
const getNewestCommitDate = vi.spyOn(git, 'getNewestCommitDate');
const route = routes.find((route) => route.entry.id === routes[4]!.id && route.locale === 'en');
assert(route, 'Expected to find English fallback route for `guides/authoring-content.mdx`.');
expect.assert(
route,
'Expected to find English fallback route for `guides/authoring-content.mdx`.'
);

generateRouteData({
props: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { assert, describe, expect, test } from 'vitest';
import { describe, expect, test } from 'vitest';
import config from 'virtual:starlight/user-config';
import { processI18nConfig } from '../../utils/i18n';

Expand All @@ -8,7 +8,7 @@ describe('processI18nConfig', () => {

expect(astroI18nConfig.defaultLocale).toBe('fr-CA');
expect(astroI18nConfig.locales).toEqual(['fr-CA']);
assert(typeof astroI18nConfig.routing !== 'string');
expect.assert(typeof astroI18nConfig.routing !== 'string');
expect(astroI18nConfig.routing?.prefixDefaultLocale).toBe(false);

// The Starlight configuration should not be modified.
Expand Down
4 changes: 2 additions & 2 deletions packages/starlight/__tests__/i18n/i18n.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { assert, describe, expect, test } from 'vitest';
import { describe, expect, test } from 'vitest';
import type { AstroConfig } from 'astro';
import config from 'virtual:starlight/user-config';
import { processI18nConfig } from '../../utils/i18n';
Expand Down Expand Up @@ -37,7 +37,7 @@ describe('processI18nConfig', () => {
},
]
`);
assert(typeof astroI18nConfig.routing !== 'string');
expect.assert(typeof astroI18nConfig.routing !== 'string');
expect(astroI18nConfig.routing?.prefixDefaultLocale).toBe(true);

// The Starlight configuration should not be modified.
Expand Down
6 changes: 3 additions & 3 deletions packages/starlight/__tests__/middleware/middleware.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { APIContext } from 'astro';
import { expect, test } from 'vitest';
import { expect, test, vi } from 'vitest';
import { onRequest } from '../../locals';
import type { StarlightRouteData } from '../../route-data';

test('starlightRoute throws when accessed outside of a Starlight page', async () => {
const context = { locals: {}, currentLocale: 'en' } as APIContext;
await onRequest(context, () => Promise.resolve(new Response()));
await onRequest(context, vi.fn());
expect(() => {
// We are testing that accessing `starlightRoute` outside of a Starlight page throws.
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
Expand All @@ -27,7 +27,7 @@ test('starlightRoute throws when accessed outside of a Starlight page', async ()

test('starlightRoute returns as expected if it has been set', async () => {
const context = { locals: {}, currentLocale: 'en' } as APIContext;
await onRequest(context, () => Promise.resolve(new Response()));
await onRequest(context, vi.fn());
context.locals.starlightRoute = { siteTitle: 'Test title' } as StarlightRouteData;
expect(context.locals.starlightRoute.siteTitle).toBe('Test title');
});
10 changes: 5 additions & 5 deletions packages/starlight/__tests__/plugins/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ describe('validation', () => {
[],
createTestPluginContext()
)
).rejects.toThrowError(/Invalid config passed to starlight integration/);
).rejects.toThrow(/Invalid config passed to starlight integration/);
});

test('validates plugins configuration before running them', async () => {
Expand All @@ -73,7 +73,7 @@ describe('validation', () => {
[{ name: 'invalid-plugin' }],
createTestPluginContext()
)
).rejects.toThrowError(/Invalid plugins config passed to starlight integration/);
).rejects.toThrow(/Invalid plugins config passed to starlight integration/);
});

test('validates configuration updates from plugins do not update the `plugins` config key', async () => {
Expand All @@ -94,7 +94,7 @@ describe('validation', () => {
],
createTestPluginContext()
)
).rejects.toThrowError(
).rejects.toThrow(
/The `test-plugin` plugin tried to update the `plugins` config key which is not supported./
);
});
Expand All @@ -117,7 +117,7 @@ describe('validation', () => {
],
createTestPluginContext()
)
).rejects.toThrowError(
).rejects.toThrow(
/The `test-plugin` plugin tried to update the `routeMiddleware` config key which is not supported./
);
});
Expand All @@ -140,7 +140,7 @@ describe('validation', () => {
],
createTestPluginContext()
)
).rejects.toThrowError(/Invalid config update provided by the 'test-plugin' plugin/);
).rejects.toThrow(/Invalid config update provided by the 'test-plugin' plugin/);
});
});

Expand Down
2 changes: 1 addition & 1 deletion packages/starlight/__tests__/remark-rehype/asides.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ Some text
:::
`
)
).rejects.toThrowError(
).rejects.toThrow(
// We are not relying on `toThrowErrorMatchingInlineSnapshot()` and our custom snapshot
// serializer in this specific test as error thrown in a remark plugin includes a dynamic file
// path.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, expect, test } from 'vitest';
import { describe, expect, test, vi } from 'vitest';
import { processFileTree } from '../../user-components/rehype-file-tree';
import { Icons, type StarlightIcon } from '../../components-internals/Icons';

Expand Down Expand Up @@ -176,6 +176,8 @@ function extractFileTree(html: string, stripIcons = true) {
return tree;
}

function expectHtmlToIncludeIcon(html: string, icon: (typeof Icons)[StarlightIcon]) {
return expect(extractFileTree(html, false)).toContain(icon.replace('/>', '>'));
}
const expectHtmlToIncludeIcon = vi.defineHelper(
(html: string, icon: (typeof Icons)[StarlightIcon]) => {
return expect(extractFileTree(html, false)).toContain(icon.replace('/>', '>'));
}
);
Loading
Loading