From dabe5a5877bdf71c1a20fd87f749f75c58674a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Perkki=C3=B6?= Date: Mon, 7 Oct 2024 10:03:59 +0300 Subject: [PATCH] test: test cases for order --- .../astro/src/default/utils/content.spec.ts | 325 ++++++++++++------ 1 file changed, 222 insertions(+), 103 deletions(-) diff --git a/packages/astro/src/default/utils/content.spec.ts b/packages/astro/src/default/utils/content.spec.ts index cc3a6a87..d4b39e99 100644 --- a/packages/astro/src/default/utils/content.spec.ts +++ b/packages/astro/src/default/utils/content.spec.ts @@ -1,8 +1,8 @@ import * as content from 'astro:content'; -import { expect, test, vi, type TaskContext } from 'vitest'; +import { describe, expect, test, vi, type TaskContext } from 'vitest'; import { getTutorial, type CollectionEntryTutorial } from './content'; -const getCollection = vi.mocked(content.getCollection); +const getCollection = vi.mocked<() => Omit[]>(content.getCollection); vi.mock('astro:content', () => ({ getCollection: vi.fn() })); // mock DEFAULT_LOCALIZATION so that we don't need to update test results everytime new keys are added there @@ -95,116 +95,235 @@ test('multiple parts', async (ctx) => { await expect(collection).toMatchFileSnapshot(snapshotName(ctx)); }); -test('lesson inherits metadata from tutorial', async () => { - const data: CollectionEntryTutorial['data'] = { - type: 'tutorial', - autoReload: true, - editor: { fileTree: { allowEdits: ['some-pattern/**'] } }, - editPageLink: 'example-link', - filesystem: { watch: true }, - focus: '/index.js', - i18n: { confirmationText: 'example' }, - mainCommand: 'ls', - prepareCommands: ['npm i'], - openInStackBlitz: { projectTitle: 'example' }, - previews: ['8080', '3000'], - template: 'vite', - terminal: { panels: ['output', 'terminal'] }, - }; - - getCollection.mockReturnValueOnce([ - { id: 'meta.md', ...tutorial, data }, - { id: '1-part/meta.md', ...part }, - { id: '1-part/1-chapter/meta.md', ...chapter }, - { id: '1-part/1-chapter/1-lesson/content.md', ...lesson }, - ]); - - const collection = await getTutorial(); - const { data: lessonData } = collection.parts['1-part'].chapters['1-chapter'].lessons['1-lesson']; - - expect(lessonData).toStrictEqual({ ...data, type: 'lesson', title: lesson.data.title }); -}); - -test('lesson inherits metadata cascaded form all higher levels', async () => { - getCollection.mockReturnValueOnce([ - { - id: 'meta.md', - ...tutorial, - data: { - ...tutorial.data, - editPageLink: 'edit link from tutorial', - focus: 'this should be overwritten', - mainCommand: 'this should be overwritten', - template: 'this should be overwritten', +describe('metadata inheriting', () => { + test('lesson inherits metadata from tutorial', async () => { + const data: CollectionEntryTutorial['data'] = { + type: 'tutorial', + autoReload: true, + editor: { fileTree: { allowEdits: ['some-pattern/**'] } }, + editPageLink: 'example-link', + filesystem: { watch: true }, + focus: '/index.js', + i18n: { confirmationText: 'example' }, + mainCommand: 'ls', + prepareCommands: ['npm i'], + openInStackBlitz: { projectTitle: 'example' }, + previews: ['8080', '3000'], + template: 'vite', + terminal: { panels: ['output', 'terminal'] }, + }; + + getCollection.mockReturnValueOnce([ + { id: 'meta.md', ...tutorial, data }, + { id: '1-part/meta.md', ...part }, + { id: '1-part/1-chapter/meta.md', ...chapter }, + { id: '1-part/1-chapter/1-lesson/content.md', ...lesson }, + ]); + + const collection = await getTutorial(); + const { data: lessonData } = collection.parts['1-part'].chapters['1-chapter'].lessons['1-lesson']; + + expect(lessonData).toStrictEqual({ ...data, type: 'lesson', title: lesson.data.title }); + }); + + test('lesson inherits metadata cascaded from all higher levels', async () => { + getCollection.mockReturnValueOnce([ + { + id: 'meta.md', + ...tutorial, + data: { + ...tutorial.data, + editPageLink: 'edit link from tutorial', + focus: 'this should be overwritten', + mainCommand: 'this should be overwritten', + template: 'this should be overwritten', + }, }, - }, - { - id: '1-part/meta.md', - ...part, - data: { - ...part.data, - focus: 'focus from part', - mainCommand: 'this should be overwritten', - template: 'this should be overwritten', + { + id: '1-part/meta.md', + ...part, + data: { + ...part.data, + focus: 'focus from part', + mainCommand: 'this should be overwritten', + template: 'this should be overwritten', + }, }, - }, - { - id: '1-part/1-chapter/meta.md', - ...chapter, - data: { - ...chapter.data, - mainCommand: 'main command from chapter', - template: 'this should be overwritten', + { + id: '1-part/1-chapter/meta.md', + ...chapter, + data: { + ...chapter.data, + mainCommand: 'main command from chapter', + template: 'this should be overwritten', + }, }, - }, - { - id: '1-part/1-chapter/1-lesson/content.md', - ...lesson, - data: { ...lesson.data, template: 'template from lesson' }, - }, - ]); + { + id: '1-part/1-chapter/1-lesson/content.md', + ...lesson, + data: { ...lesson.data, template: 'template from lesson' }, + }, + ]); - const collection = await getTutorial(); - const { data: lessonData } = collection.parts['1-part'].chapters['1-chapter'].lessons['1-lesson']; + const collection = await getTutorial(); + const { data: lessonData } = collection.parts['1-part'].chapters['1-chapter'].lessons['1-lesson']; - expect(lessonData.editPageLink).toBe('edit link from tutorial'); - expect(lessonData.focus).toBe('focus from part'); - expect(lessonData.mainCommand).toBe('main command from chapter'); - expect(lessonData.template).toBe('template from lesson'); + expect(lessonData.editPageLink).toBe('edit link from tutorial'); + expect(lessonData.focus).toBe('focus from part'); + expect(lessonData.mainCommand).toBe('main command from chapter'); + expect(lessonData.template).toBe('template from lesson'); + }); }); -test('throws when tutorial metadata not found', async () => { - getCollection.mockReturnValueOnce([ - { id: '1-part/meta.md', ...part }, - { id: '1-part/1-chapter/meta.md', ...chapter }, - { id: '1-part/1-chapter/1-first/content.md', ...lesson }, - ]); - - await expect(getTutorial).rejects.toThrowErrorMatchingInlineSnapshot( - `[Error: Could not find tutorial 'meta.md' file]`, - ); -}); - -test('throws when part not found', async () => { - getCollection.mockReturnValueOnce([ - { id: 'meta.md', ...tutorial }, - { id: '2-part/meta.md', ...part }, - { id: '1-part/1-chapter/meta.md', ...chapter }, - { id: '1-part/1-chapter/1-first/content.md', ...lesson }, - ]); - - await expect(getTutorial).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: Could not find part '1-part']`); +describe('ordering', () => { + test('parts are ordered by default', async () => { + getCollection.mockReturnValueOnce([ + { id: 'meta.md', ...tutorial }, + { id: '2-part/meta.md', ...part }, + { id: '3-part/meta.md', ...part }, + { id: '1-part/meta.md', ...part }, + ]); + + const collection = await getTutorial(); + const parts = collection.parts; + + expect(parts['1-part'].order).toBe(0); + expect(parts['2-part'].order).toBe(1); + expect(parts['3-part'].order).toBe(2); + }); + + test('parts are ordered by metadata', async () => { + getCollection.mockReturnValueOnce([ + { + id: 'meta.md', + ...tutorial, + data: { ...tutorial.data, parts: ['3-part', '1-part', '2-part'] }, + }, + { id: '2-part/meta.md', ...part }, + { id: '3-part/meta.md', ...part }, + { id: '1-part/meta.md', ...part }, + ]); + + const collection = await getTutorial(); + const parts = collection.parts; + + expect(parts['3-part'].order).toBe(0); + expect(parts['1-part'].order).toBe(1); + expect(parts['2-part'].order).toBe(2); + }); + + test('chapters are ordered by default', async () => { + getCollection.mockReturnValueOnce([ + { id: 'meta.md', ...tutorial }, + { id: '1-part/meta.md', ...part }, + { id: '1-part/3-chapter/meta.md', ...chapter }, + { id: '1-part/1-chapter/meta.md', ...chapter }, + { id: '1-part/2-chapter/meta.md', ...chapter }, + ]); + + const collection = await getTutorial(); + const chapters = collection.parts['1-part'].chapters; + + expect(chapters['1-chapter'].order).toBe(0); + expect(chapters['2-chapter'].order).toBe(1); + expect(chapters['3-chapter'].order).toBe(2); + }); + + test('chapters are ordered by metadata', async () => { + getCollection.mockReturnValueOnce([ + { id: 'meta.md', ...tutorial }, + { id: '1-part/meta.md', ...part, data: { ...part.data, chapters: ['3-chapter', '1-chapter', '2-chapter'] } }, + { id: '1-part/1-chapter/meta.md', ...chapter }, + { id: '1-part/2-chapter/meta.md', ...chapter }, + { id: '1-part/3-chapter/meta.md', ...chapter }, + ]); + + const collection = await getTutorial(); + const chapters = collection.parts['1-part'].chapters; + + expect(chapters['3-chapter'].order).toBe(0); + expect(chapters['1-chapter'].order).toBe(1); + expect(chapters['2-chapter'].order).toBe(2); + }); + + test('lessons are ordered by default', async () => { + getCollection.mockReturnValueOnce([ + { id: 'meta.md', ...tutorial }, + { id: '1-part/meta.md', ...part }, + { id: '1-part/1-chapter/meta.md', ...chapter }, + { id: '1-part/1-chapter/2-lesson/meta.md', ...lesson }, + { id: '1-part/1-chapter/3-lesson/meta.md', ...lesson }, + { id: '1-part/1-chapter/1-lesson/meta.md', ...lesson }, + ]); + + const collection = await getTutorial(); + const lessons = collection.parts['1-part'].chapters['1-chapter'].lessons; + + expect(lessons['1-lesson'].order).toBe(0); + expect(lessons['2-lesson'].order).toBe(1); + expect(lessons['3-lesson'].order).toBe(2); + }); + + test('lessons are ordered by metadata', async () => { + getCollection.mockReturnValueOnce([ + { id: 'meta.md', ...tutorial }, + { id: '1-part/meta.md', ...part }, + { + id: '1-part/1-chapter/meta.md', + ...chapter, + data: { + ...chapter.data, + lessons: ['3-lesson', '1-lesson', '2-lesson'], + }, + }, + { id: '1-part/1-chapter/2-lesson/meta.md', ...lesson }, + { id: '1-part/1-chapter/3-lesson/meta.md', ...lesson }, + { id: '1-part/1-chapter/1-lesson/meta.md', ...lesson }, + ]); + + const collection = await getTutorial(); + const lessons = collection.parts['1-part'].chapters['1-chapter'].lessons; + + expect(lessons['3-lesson'].order).toBe(0); + expect(lessons['1-lesson'].order).toBe(1); + expect(lessons['2-lesson'].order).toBe(2); + }); }); -test('throws when chapter not found', async () => { - getCollection.mockReturnValueOnce([ - { id: 'meta.md', ...tutorial }, - { id: '1-part/meta.md', ...part }, - { id: '1-part/2-chapter/meta.md', ...chapter }, - { id: '1-part/1-chapter/1-first/content.md', ...lesson }, - ]); - - await expect(getTutorial).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: Could not find chapter '1-chapter']`); +describe('missing parts', () => { + test('throws when tutorial metadata not found', async () => { + getCollection.mockReturnValueOnce([ + { id: '1-part/meta.md', ...part }, + { id: '1-part/1-chapter/meta.md', ...chapter }, + { id: '1-part/1-chapter/1-first/content.md', ...lesson }, + ]); + + await expect(getTutorial).rejects.toThrowErrorMatchingInlineSnapshot( + `[Error: Could not find tutorial 'meta.md' file]`, + ); + }); + + test('throws when part not found', async () => { + getCollection.mockReturnValueOnce([ + { id: 'meta.md', ...tutorial }, + { id: '2-part/meta.md', ...part }, + { id: '1-part/1-chapter/meta.md', ...chapter }, + { id: '1-part/1-chapter/1-first/content.md', ...lesson }, + ]); + + await expect(getTutorial).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: Could not find part '1-part']`); + }); + + test('throws when chapter not found', async () => { + getCollection.mockReturnValueOnce([ + { id: 'meta.md', ...tutorial }, + { id: '1-part/meta.md', ...part }, + { id: '1-part/2-chapter/meta.md', ...chapter }, + { id: '1-part/1-chapter/1-first/content.md', ...lesson }, + ]); + + await expect(getTutorial).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: Could not find chapter '1-chapter']`); + }); }); const tutorial = {