Skip to content

Commit

Permalink
Add the first integration test (#124)
Browse files Browse the repository at this point in the history
  • Loading branch information
illright authored Jan 16, 2025
1 parent 556829e commit 72f1981
Show file tree
Hide file tree
Showing 20 changed files with 373 additions and 16 deletions.
5 changes: 5 additions & 0 deletions .changeset/flat-months-bow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'steiger': patch
---

The diagnostics from a single rule are now sorted by path in alphabetical order
4 changes: 2 additions & 2 deletions .github/workflows/bundle-size-trusted.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ jobs:
}
}
const fs = require('fs');
const sizes = parseDuOutput(fs.readFileSync(`sizes-${${{ toJson(github.base_ref) }}}.txt`, 'utf8'));
const sizesPR = parseDuOutput(fs.readFileSync(`sizes-${${{ toJson(github.head_ref) }}}.txt`, 'utf8'));
const sizes = parseDuOutput(fs.readFileSync('sizes-master.txt', 'utf8'));
const sizesPR = parseDuOutput(fs.readFileSync(`sizes-${${{ toJson(github.event.workflow_run.head_branch) }}}.txt`, 'utf8'));
core.summary.addHeading('📊 Package size report', '3');
core.summary.addTable([
['Package', 'Before', 'After'].map((data) => ({ data, header: true })),
Expand Down
1 change: 1 addition & 0 deletions examples/kitchen-sink-of-fsd-issues/src/app/ui/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const App = {}
1 change: 1 addition & 0 deletions examples/kitchen-sink-of-fsd-issues/src/app/ui/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { App } from './App'
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { App } from '@/app/ui/App'

console.log(App)
12 changes: 12 additions & 0 deletions examples/kitchen-sink-of-fsd-issues/tsconfig.app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"module": "ESNext",
"jsx": "react-jsx",
"moduleResolution": "Bundler",
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src"]
}
5 changes: 4 additions & 1 deletion examples/kitchen-sink-of-fsd-issues/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
{}
{
"files": [],
"references": [{ "path": "./tsconfig.app.json" }]
}
10 changes: 10 additions & 0 deletions integration-tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# How to write integration tests

> [!NOTE]
> You should develop tests on either Mac or Linux. If you have a Windows machine, consider using a [devcontainer](containers.dev).
>
> This is mainly because the Unicode symbols used in the output are always replaced by fallbacks on Windows, so converting outputs from Windows to POSIX isn't practical.
Create a new file with the `.test.ts` extension in the `tests/` folder. Use `tests/smoke.test.ts` as a reference on how to set up a temporary folder for the project and execute Steiger.

Store your output snapshots in `__snapshots__` with the `-posix.txt` extension. After you wrote your test, run `pnpm update-windows-snapshots` to copy over the changes in snapshots.
1 change: 1 addition & 0 deletions integration-tests/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from '@steiger/eslint-config'
37 changes: 37 additions & 0 deletions integration-tests/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"private": true,
"name": "@steiger/integration-tests",
"description": "Integration tests for Steiger",
"version": "0.1.0",
"scripts": {
"test": "vitest run",
"update-windows-snapshots": "node ./scripts/update-windows-snapshots.mjs"
},
"exports": {
".": "./src/index.ts"
},
"type": "module",
"authors": [
{
"name": "Lev Chelyadinov",
"email": "[email protected]",
"url": "https://github.com/illright"
}
],
"devDependencies": {
"@steiger/eslint-config": "workspace:*",
"@steiger/tsconfig": "workspace:*",
"@total-typescript/ts-reset": "^0.6.1",
"@types/node": "^18.11.9",
"eslint": "^9.16.0",
"figures": "^6.1.0",
"get-bin-path": "^11.0.0",
"prettier": "^3.4.2",
"tinyexec": "^0.3.1",
"typescript": "^5.7.2",
"vitest": "^3.0.0-beta.2"
},
"dependencies": {
"steiger": "workspace:*"
}
}
2 changes: 2 additions & 0 deletions integration-tests/reset.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Do not add any other lines of code to this file!
import '@total-typescript/ts-reset'
23 changes: 23 additions & 0 deletions integration-tests/scripts/update-windows-snapshots.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Run this script on Mac or Linux when you update test snapshots to port these changes over to Windows snapshots.
*
* $ pnpm run update-windows-snapshots
*/

import * as fs from 'node:fs/promises'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { replaceSymbols } from 'figures'

const snapshotsFolder = join(dirname(fileURLToPath(import.meta.url)), '../tests/__snapshots__')

// Go through each POSIX snapshot and replace the forward slashes in diagnostic paths with backslashes
for (const file of await fs.readdir(snapshotsFolder)) {
if (file.endsWith('-posix.txt')) {
const windowsSnapshotName = file.slice(0, -'-posix.txt'.length) + '-windows.txt'
const updatedSnapshot = replaceSymbols(await fs.readFile(join(snapshotsFolder, file), 'utf8'), {
useFallback: true,
}).replace(/(?<=.+)\//gm, '\\')
await fs.writeFile(join(snapshotsFolder, windowsSnapshotName), updatedSnapshot)
}
}
45 changes: 45 additions & 0 deletions integration-tests/tests/__snapshots__/smoke-stderr-posix.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

┌ src/entities/user/api/getUser.ts
✘ Forbidden import from higher layer "app".
└ fsd/forbidden-imports (​https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/forbidden-imports​)

┌ src/entities
✘ Inconsistent pluralization of slice names. Prefer all plural names
✔ Auto-fixable
└ fsd/inconsistent-naming (​https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/inconsistent-naming​)

┌ src/entities/user
✘ This slice has no references. Consider removing it.
└ fsd/insignificant-slice (​https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/insignificant-slice​)

┌ src/entities/users
✘ This slice has no references. Consider removing it.
└ fsd/insignificant-slice (​https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/insignificant-slice​)

┌ src/entities/user/api/getUser.ts
✘ Forbidden sidestep of public API when importing from "@/app/ui/App".
└ fsd/no-public-api-sidestep (​https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/no-public-api-sidestep​)

┌ src/entities/user/ui/api
✘ Having a folder with the name "api" inside a segment could be confusing because that name is commonly used for segments. Consider renaming it.
└ fsd/no-reserved-folder-names (​https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/no-reserved-folder-names​)

┌ src/app/ui
✘ Layer "app" should not have "ui" segment.
└ fsd/no-ui-in-app (​https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/no-ui-in-app​)

┌ src/processes
✘ Layer "processes" is deprecated, avoid using it
└ fsd/no-processes (​https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/no-processes​)

────────────────────────────────────────────────────────
Found 8 errors (1 can be fixed automatically with --fix)

45 changes: 45 additions & 0 deletions integration-tests/tests/__snapshots__/smoke-stderr-windows.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

┌ src\entities\user\api\getUser.ts
× Forbidden import from higher layer "app".
└ fsd/forbidden-imports (​https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/forbidden-imports​)

┌ src\entities
× Inconsistent pluralization of slice names. Prefer all plural names
√ Auto-fixable
└ fsd/inconsistent-naming (​https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/inconsistent-naming​)

┌ src\entities\user
× This slice has no references. Consider removing it.
└ fsd/insignificant-slice (​https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/insignificant-slice​)

┌ src\entities\users
× This slice has no references. Consider removing it.
└ fsd/insignificant-slice (​https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/insignificant-slice​)

┌ src\entities\user\api\getUser.ts
× Forbidden sidestep of public API when importing from "@/app/ui/App".
└ fsd/no-public-api-sidestep (​https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/no-public-api-sidestep​)

┌ src\entities\user\ui\api
× Having a folder with the name "api" inside a segment could be confusing because that name is commonly used for segments. Consider renaming it.
└ fsd/no-reserved-folder-names (​https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/no-reserved-folder-names​)

┌ src\app\ui
× Layer "app" should not have "ui" segment.
└ fsd/no-ui-in-app (​https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/no-ui-in-app​)

┌ src\processes
× Layer "processes" is deprecated, avoid using it
└ fsd/no-processes (​https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/no-processes​)

────────────────────────────────────────────────────────
Found 8 errors (1 can be fixed automatically with --fix)

24 changes: 24 additions & 0 deletions integration-tests/tests/smoke.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as fs from 'node:fs/promises'
import os from 'node:os'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { exec } from 'tinyexec'

import { expect, test } from 'vitest'

import { getSteigerBinPath } from '../utils/get-bin-path.js'

const temporaryDirectory = await fs.realpath(os.tmpdir())
const steiger = await getSteigerBinPath()
const kitchenSinkExample = join(dirname(fileURLToPath(import.meta.url)), '../../examples/kitchen-sink-of-fsd-issues')
const pathPlatform = os.platform() === 'win32' ? 'windows' : 'posix'

test('basic functionality in the kitchen sink example project', async () => {
const project = join(temporaryDirectory, 'smoke')
await fs.rm(project, { recursive: true, force: true })
await fs.cp(kitchenSinkExample, project, { recursive: true })

const { stderr } = await exec('node', [steiger, 'src'], { nodeOptions: { cwd: project, env: { NO_COLOR: '1' } } })

await expect(stderr).toMatchFileSnapshot(join('__snapshots__', `smoke-stderr-${pathPlatform}.txt`))
})
7 changes: 7 additions & 0 deletions integration-tests/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "@steiger/tsconfig/base.json",
"include": ["./tests", "./utils", "./scripts", "./reset.d.ts"],
"compilerOptions": {
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
}
}
22 changes: 22 additions & 0 deletions integration-tests/utils/get-bin-path.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { promises as fs } from 'node:fs'
import * as process from 'node:process'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { getBinPath } from 'get-bin-path'

/**
* Resolve the full path to the built JS file of Steiger.
*
* Rejects if the file doesn't exist.
*/
export async function getSteigerBinPath() {
const steiger = (await getBinPath({ cwd: join(dirname(fileURLToPath(import.meta.url)), '../../packages/steiger') }))!
try {
await fs.stat(steiger)
} catch {
console.error('Run `turbo build` before running integration tests')
process.exit(1)
}

return steiger
}
21 changes: 9 additions & 12 deletions packages/steiger/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,22 @@ async function runRules({ vfs, rules }: { vfs: Folder; rules: Array<Rule> }) {
const vfsWithoutGlobalIgnores = removeGlobalIgnoreFromVfs(vfs, getGlobalIgnores())

const ruleResults = await Promise.all(rules.map((rule) => runRule(vfsWithoutGlobalIgnores, rule)))
return ruleResults.flatMap((r, ruleResultsIndex) => {
const { diagnostics } = r
if (diagnostics.length === 0) {
return []
}

return ruleResults.flatMap(({ diagnostics }, ruleResultsIndex) => {
const ruleName = rules[ruleResultsIndex].name
const severities = calculateFinalSeverities(
vfsWithoutGlobalIgnores,
ruleName,
diagnostics.map((d) => d.location.path),
)

return diagnostics.map((d, index) => ({
...d,
ruleName,
getRuleDescriptionUrl,
severity: severities[index],
}))
return diagnostics
.sort((a, b) => a.location.path.localeCompare(b.location.path))
.map((d, index) => ({
...d,
ruleName,
getRuleDescriptionUrl,
severity: severities[index],
}))
})
}

Expand Down
Loading

0 comments on commit 72f1981

Please sign in to comment.