Skip to content

Commit

Permalink
Fix file mocking on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
illright committed Jun 16, 2024
1 parent 2414bcf commit 2a508e1
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 100 deletions.
25 changes: 24 additions & 1 deletion packages/steiger-plugin-fsd/src/_lib/prepare-test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { join } from 'node:path'
import { join, sep } from 'node:path'
import type { readFileSync, existsSync } from 'node:fs'
import type { Folder, File, FsdRoot } from '@feature-sliced/filesystem'
import type { Diagnostic } from '../types.js'
import { vi } from 'vitest'

/** Parse a multi-line indented string with emojis for files and folders into an FSD root. */
export function parseIntoFsdRoot(fsMarkup: string): FsdRoot {
Expand Down Expand Up @@ -42,6 +44,27 @@ export function joinFromRoot(...segments: Array<string>) {
return join('/', ...segments)
}

export function createFsMocks(mockedFiles: Record<string, string>, original: typeof import('fs')) {
const normalizedMockedFiles = Object.fromEntries(
Object.entries(mockedFiles).map(([path, content]) => [path.replace(/\//g, sep), content]),
)

return {
...original,
readFileSync: vi.fn(((path, options) => {
if (typeof path === 'string' && path in normalizedMockedFiles) {
return normalizedMockedFiles[path as keyof typeof normalizedMockedFiles]
} else {
return original.readFileSync(path, options)
}
}) as typeof readFileSync),
existsSync: vi.fn(((path) =>
Object.keys(normalizedMockedFiles).some(
(key) => key === path || key.startsWith(path + sep),
)) as typeof existsSync),
}
}

if (import.meta.vitest) {
const { test, expect } = import.meta.vitest

Expand Down
52 changes: 21 additions & 31 deletions packages/steiger-plugin-fsd/src/forbidden-imports/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { expect, it, vi } from 'vitest'
import type { readFileSync } from 'node:fs'
import { sep } from 'node:path'

import { parseIntoFsdRoot } from '../_lib/prepare-test.js'
import forbiddenImports from './index.js'
Expand All @@ -13,36 +11,28 @@ vi.mock('tsconfck', async (importOriginal) => {
})

vi.mock('node:fs', async (importOriginal) => {
const original = await importOriginal<typeof import('fs')>()
const originalFs = await importOriginal<typeof import('fs')>()
const { createFsMocks } = await import('../_lib/prepare-test.js')

const mockedFiles = {
'/shared/ui/styles.ts': '',
'/shared/ui/Button.tsx': 'import styles from "./styles";',
'/shared/ui/TextField.tsx': 'import styles from "./styles";',
'/shared/ui/index.ts': '',
'/entities/user/ui/UserAvatar.tsx': 'import { Button } from "@/shared/ui"',
'/entities/user/index.ts': '',
'/entities/product/ui/ProductCard.tsx': 'import { UserAvatar } from "@/entities/user"',
'/entities/product/index.ts': '',
'/features/comments/ui/CommentCard.tsx': 'import { styles } from "@/pages/editor"',
'/features/comments/index.ts': '',
'/pages/editor/ui/styles.ts': '',
'/pages/editor/ui/EditorPage.tsx': 'import { Button } from "@/shared/ui"; import { Editor } from "./Editor"',
'/pages/editor/ui/Editor.tsx': 'import { TextField } from "@/shared/ui"',
'/pages/editor/index.ts': '',
}

return {
...original,
readFileSync: vi.fn(((path, options) => {
if (typeof path === 'string' && path in mockedFiles) {
return mockedFiles[path as keyof typeof mockedFiles]
} else {
return original.readFileSync(path, options)
}
}) as typeof readFileSync),
existsSync: vi.fn((path) => Object.keys(mockedFiles).some((key) => key === path || key.startsWith(path + sep))),
}
return createFsMocks(
{
'/shared/ui/styles.ts': '',
'/shared/ui/Button.tsx': 'import styles from "./styles";',
'/shared/ui/TextField.tsx': 'import styles from "./styles";',
'/shared/ui/index.ts': '',
'/entities/user/ui/UserAvatar.tsx': 'import { Button } from "@/shared/ui"',
'/entities/user/index.ts': '',
'/entities/product/ui/ProductCard.tsx': 'import { UserAvatar } from "@/entities/user"',
'/entities/product/index.ts': '',
'/features/comments/ui/CommentCard.tsx': 'import { styles } from "@/pages/editor"',
'/features/comments/index.ts': '',
'/pages/editor/ui/styles.ts': '',
'/pages/editor/ui/EditorPage.tsx': 'import { Button } from "@/shared/ui"; import { Editor } from "./Editor"',
'/pages/editor/ui/Editor.tsx': 'import { TextField } from "@/shared/ui"',
'/pages/editor/index.ts': '',
},
originalFs,
)
})

it('reports no errors on a project with only correct imports', async () => {
Expand Down
60 changes: 25 additions & 35 deletions packages/steiger-plugin-fsd/src/insignificant-slice/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { expect, it, vi } from 'vitest'
import type { readFileSync } from 'node:fs'
import { sep } from 'node:path'

import { compareMessages, parseIntoFsdRoot } from '../_lib/prepare-test.js'
import insignificantSlice from './index.js'
Expand All @@ -13,40 +11,32 @@ vi.mock('tsconfck', async (importOriginal) => {
})

vi.mock('node:fs', async (importOriginal) => {
const original = await importOriginal<typeof import('fs')>()
const originalFs = await importOriginal<typeof import('fs')>()
const { createFsMocks } = await import('../_lib/prepare-test.js')

const mockedFiles = {
'/shared/ui/styles.ts': '',
'/shared/ui/Button.tsx': 'import styles from "./styles";',
'/shared/ui/TextField.tsx': 'import styles from "./styles";',
'/shared/ui/index.ts': '',
'/entities/user/ui/UserAvatar.tsx': 'import { Button } from "@/shared/ui"',
'/entities/user/index.ts': '',
'/entities/product/ui/ProductCard.tsx': '',
'/entities/product/index.ts': '',
'/features/comments/ui/CommentCard.tsx': '',
'/features/comments/index.ts': '',
'/pages/editor/ui/EditorPage.tsx':
'import { Button } from "@/shared/ui"; import { Editor } from "./Editor"; import { CommentCard } from "@/features/comments"; import { UserAvatar } from "@/entities/user"',
'/pages/editor/ui/Editor.tsx':
'import { TextField } from "@/shared/ui"; import { UserAvatar } from "@/entities/user"',
'/pages/editor/index.ts': '',
'/pages/settings/ui/SettingsPage.tsx':
'import { Button } from "@/shared/ui"; import { CommentCard } from "@/features/comments"',
'/pages/settings/index.ts': '',
}

return {
...original,
readFileSync: vi.fn(((path, options) => {
if (typeof path === 'string' && path in mockedFiles) {
return mockedFiles[path as keyof typeof mockedFiles]
} else {
return original.readFileSync(path, options)
}
}) as typeof readFileSync),
existsSync: vi.fn((path) => Object.keys(mockedFiles).some((key) => key === path || key.startsWith(path + sep))),
}
return createFsMocks(
{
'/shared/ui/styles.ts': '',
'/shared/ui/Button.tsx': 'import styles from "./styles";',
'/shared/ui/TextField.tsx': 'import styles from "./styles";',
'/shared/ui/index.ts': '',
'/entities/user/ui/UserAvatar.tsx': 'import { Button } from "@/shared/ui"',
'/entities/user/index.ts': '',
'/entities/product/ui/ProductCard.tsx': '',
'/entities/product/index.ts': '',
'/features/comments/ui/CommentCard.tsx': '',
'/features/comments/index.ts': '',
'/pages/editor/ui/EditorPage.tsx':
'import { Button } from "@/shared/ui"; import { Editor } from "./Editor"; import { CommentCard } from "@/features/comments"; import { UserAvatar } from "@/entities/user"',
'/pages/editor/ui/Editor.tsx':
'import { TextField } from "@/shared/ui"; import { UserAvatar } from "@/entities/user"',
'/pages/editor/index.ts': '',
'/pages/settings/ui/SettingsPage.tsx':
'import { Button } from "@/shared/ui"; import { CommentCard } from "@/features/comments"',
'/pages/settings/index.ts': '',
},
originalFs,
)
})

it('reports no errors on a project with slices only on the Pages layer', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { expect, it, vi } from 'vitest'
import type { readFileSync } from 'node:fs'
import { sep } from 'node:path'

import { parseIntoFsdRoot } from '../_lib/prepare-test.js'
import noPublicApiSidestep from './index.js'
Expand All @@ -13,38 +11,30 @@ vi.mock('tsconfck', async (importOriginal) => {
})

vi.mock('node:fs', async (importOriginal) => {
const original = await importOriginal<typeof import('fs')>()
const originalFs = await importOriginal<typeof import('fs')>()
const { createFsMocks } = await import('../_lib/prepare-test.js')

const mockedFiles = {
'/shared/ui/styles.ts': '',
'/shared/ui/Button.tsx': 'import styles from "./styles";',
'/shared/ui/TextField.tsx': 'import styles from "./styles";',
'/shared/ui/index.ts': '',
'/entities/user/ui/UserAvatar.tsx': 'import { Button } from "@/shared/ui"',
'/entities/user/index.ts': '',
'/entities/product/ui/ProductCard.tsx': 'import { UserAvatar } from "@/entities/user"',
'/entities/product/index.ts': '',
'/features/comments/ui/CommentCard.tsx': 'import { styles } from "@/pages/editor"',
'/features/comments/index.ts': '',
'/pages/editor/ui/styles.ts': '',
'/pages/editor/ui/EditorPage.tsx': 'import { Button } from "@/shared/ui"; import { Editor } from "./Editor"',
'/pages/editor/ui/Editor.tsx':
'import { TextField } from "@/shared/ui"; import { ProductCard } from "@/entities/product/ui/ProductCard.tsx"',
'/pages/editor/ui/SubmitButton.tsx': 'import { Button } from "@/shared/ui/Button"',
'/pages/editor/index.ts': '',
}

return {
...original,
readFileSync: vi.fn(((path, options) => {
if (typeof path === 'string' && path in mockedFiles) {
return mockedFiles[path as keyof typeof mockedFiles]
} else {
return original.readFileSync(path, options)
}
}) as typeof readFileSync),
existsSync: vi.fn((path) => Object.keys(mockedFiles).some((key) => key === path || key.startsWith(path + sep))),
}
return createFsMocks(
{
'/shared/ui/styles.ts': '',
'/shared/ui/Button.tsx': 'import styles from "./styles";',
'/shared/ui/TextField.tsx': 'import styles from "./styles";',
'/shared/ui/index.ts': '',
'/entities/user/ui/UserAvatar.tsx': 'import { Button } from "@/shared/ui"',
'/entities/user/index.ts': '',
'/entities/product/ui/ProductCard.tsx': 'import { UserAvatar } from "@/entities/user"',
'/entities/product/index.ts': '',
'/features/comments/ui/CommentCard.tsx': 'import { styles } from "@/pages/editor"',
'/features/comments/index.ts': '',
'/pages/editor/ui/styles.ts': '',
'/pages/editor/ui/EditorPage.tsx': 'import { Button } from "@/shared/ui"; import { Editor } from "./Editor"',
'/pages/editor/ui/Editor.tsx':
'import { TextField } from "@/shared/ui"; import { ProductCard } from "@/entities/product/ui/ProductCard.tsx"',
'/pages/editor/ui/SubmitButton.tsx': 'import { Button } from "@/shared/ui/Button"',
'/pages/editor/index.ts': '',
},
originalFs,
)
})

it('reports no errors on a project without public API sidesteps', async () => {
Expand Down

0 comments on commit 2a508e1

Please sign in to comment.