diff --git a/.github/workflows/integration-test-cli.yaml b/.github/workflows/integration-test-cli.yaml index 6580f027c..f7504105f 100644 --- a/.github/workflows/integration-test-cli.yaml +++ b/.github/workflows/integration-test-cli.yaml @@ -8,8 +8,20 @@ jobs: cli-integration-test: name: CLI Integration Tests # Note: `prepare-release.yaml` sets this commit message - if: ${{ contains(github.event.pull_request.title, 'release CLI') || github.event_name == 'workflow_dispatch' }} - runs-on: ubuntu-latest + if: ${{ contains(github.event.pull_request.title, 'release CLI') || github.event_name == 'workflow_dispatch' || github.ref_name == 'main' }} + + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + node-version: [18, 20, 22] + include: + - os: macos-latest + node_version: 20 + - os: windows-latest + node_version: 20.13.1 + steps: - name: Checkout uses: actions/checkout@v4 @@ -17,6 +29,8 @@ jobs: fetch-depth: 0 - uses: ./.github/actions/setup-and-build + with: + node-version: ${{ matrix.node-version }} - name: Update template's versions working-directory: ./packages/cli diff --git a/integration/cli/create-tutorial.test.ts b/integration/cli/create-tutorial.test.ts index c032af957..673fc6a5b 100644 --- a/integration/cli/create-tutorial.test.ts +++ b/integration/cli/create-tutorial.test.ts @@ -4,17 +4,16 @@ import { execa } from 'execa'; import { temporaryDirectory } from 'tempy'; import { describe, beforeEach, afterAll, expect, it } from 'vitest'; +const isWindows = process.platform === 'win32'; const baseDir = path.resolve(__dirname, '../..'); - const cli = path.join(baseDir, 'packages/cli/dist/index.js'); +const tmp = temporaryDirectory(); interface TestContext { projectName: string; dest: string; } -const tmp = temporaryDirectory(); - beforeEach(async (context) => { context.projectName = Math.random().toString(36).substring(7); context.dest = path.join(tmp, context.projectName); @@ -35,7 +34,7 @@ describe.each(['npm', 'pnpm', 'yarn'])('%s', (packageManager) => { expect(filesToJSON(projectFiles)).toMatchFileSnapshot(`${snapshotPrefix}-created.json`); }); - it('should create and build a project', async ({ projectName, dest }) => { + it.skipIf(isWindows)('should create and build a project', async ({ projectName, dest }) => { await createProject(projectName, packageManager, { cwd: tmp, install: true }); await execa(packageManager, ['run', 'build'], { @@ -50,19 +49,22 @@ describe.each(['npm', 'pnpm', 'yarn'])('%s', (packageManager) => { expect(filesToJSON(distFiles)).toMatchFileSnapshot(`${snapshotPrefix}-built.json`); }); - it('created project contains overwritten UnoCSS config', async ({ projectName, dest }) => { - await createProject(projectName, packageManager, { cwd: tmp }); + it.skipIf(isWindows)( + 'created project contains overwritten UnoCSS config', + async ({ projectName, dest }) => { + await createProject(projectName, packageManager, { cwd: tmp }); - const unoConfig = await fs.readFile(`${dest}/uno.config.ts`, 'utf8'); + const unoConfig = await fs.readFile(`${dest}/uno.config.ts`, 'utf8'); - expect(unoConfig).toBe(`\ + expect(unoConfig).toBe(`\ import { defineConfig } from '@tutorialkit/theme'; export default defineConfig({ // add your UnoCSS config here: https://unocss.dev/guide/config-file }); `); - }); + }, + ); }); async function createProject(name: string, packageManager: string, options: { cwd: string; install?: boolean }) { diff --git a/integration/package.json b/integration/package.json index 600ccb522..c085bef35 100644 --- a/integration/package.json +++ b/integration/package.json @@ -6,6 +6,7 @@ "test": "vitest --testTimeout=300000" }, "dependencies": { + "@tutorialkit/theme": "workspace:*", "execa": "^9.2.0", "tempy": "^3.1.0", "vitest": "^2.1.1" diff --git a/integration/theme-resolving/inline-content.test.ts b/integration/theme-resolving/inline-content.test.ts new file mode 100644 index 000000000..1a49ada6f --- /dev/null +++ b/integration/theme-resolving/inline-content.test.ts @@ -0,0 +1,30 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { getInlineContentForPackage } from '@tutorialkit/theme'; +import { execa } from 'execa'; +import { temporaryDirectory } from 'tempy'; +import { afterAll, expect, test } from 'vitest'; + +const baseDir = path.resolve(__dirname, '../..'); +const cli = path.join(baseDir, 'packages/cli/dist/index.js'); +const tmp = temporaryDirectory(); + +afterAll(async () => { + await fs.rm(tmp, { force: true, recursive: true }); +}); + +test('getInlineContentForPackage finds files from @tutorialkit/astro', async () => { + await execa( + 'node', + [cli, 'create', 'theme-test', '--install', '--no-git', '--no-start', '--package-manager', 'pnpm', '--defaults'], + { cwd: tmp }, + ); + + const content = getInlineContentForPackage({ + name: '@tutorialkit/astro', + pattern: '/dist/default/**/*.astro', + root: `${tmp}/theme-test`, + }); + + expect(content.length).toBeGreaterThan(0); +}); diff --git a/packages/theme/package.json b/packages/theme/package.json index 34c53f199..645bb3b65 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -28,7 +28,8 @@ ], "scripts": { "build": "tsc -b", - "dev": "pnpm run build --watch --preserveWatchOutput" + "dev": "pnpm run build --watch --preserveWatchOutput", + "test": "vitest" }, "dependencies": { "@iconify-json/ph": "^1.1.13", @@ -38,6 +39,7 @@ }, "devDependencies": { "@types/node": "^22.4.1", - "typescript": "^5.4.5" + "typescript": "^5.4.5", + "vitest": "^2.1.1" } } diff --git a/packages/theme/src/index.spec.ts b/packages/theme/src/index.spec.ts new file mode 100644 index 000000000..28b0fa802 --- /dev/null +++ b/packages/theme/src/index.spec.ts @@ -0,0 +1,15 @@ +import { fileURLToPath, URL } from 'node:url'; +import { expect, test } from 'vitest'; +import { getInlineContentForPackage } from './index.js'; + +const root = fileURLToPath(new URL('../../template', import.meta.url)); + +test('getInlineContentForPackage finds files from @tutorialkit/astro', () => { + const content = getInlineContentForPackage({ + name: '@tutorialkit/astro', + pattern: '/dist/default/**/*.astro', + root, + }); + + expect(content.length).toBeGreaterThan(0); +}); diff --git a/packages/theme/src/index.ts b/packages/theme/src/index.ts index 34ff2f92a..d561be68b 100644 --- a/packages/theme/src/index.ts +++ b/packages/theme/src/index.ts @@ -49,7 +49,7 @@ export function getInlineContentForPackage({ name, pattern, root }: { name: stri const packageRoot = resolve(require.resolve(`${name}/package.json`, { paths: [root] }), '..'); // work-around for https://github.com/mrmlnc/fast-glob/issues/452 - const packagePattern = convertPathToPattern(packageRoot.replace('\\@', '/@')); + const packagePattern = convertPathToPattern(packageRoot.replaceAll('\\@', '/@')); return globSync(`${packagePattern}${pattern}`).map((filePath) => () => fs.readFile(filePath, { encoding: 'utf8' })); } catch { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 12a266017..152a529cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -272,6 +272,9 @@ importers: integration: dependencies: + '@tutorialkit/theme': + specifier: workspace:* + version: link:../packages/theme execa: specifier: ^9.2.0 version: 9.2.0 @@ -714,6 +717,9 @@ importers: typescript: specifier: ^5.4.5 version: 5.5.3 + vitest: + specifier: ^2.1.1 + version: 2.1.1(@types/node@22.4.2) packages/types: dependencies: