Skip to content

Commit

Permalink
Merge pull request #7 from mizdra/add-examples
Browse files Browse the repository at this point in the history
Add examples
  • Loading branch information
mizdra authored Jul 2, 2023
2 parents f8b37f9 + 739d1e8 commit 9d24578
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 4 deletions.
174 changes: 170 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ $ npm i -D @mizdra/inline-fixture-files
## Features

- Write fixture files inline
- TypeScript support
- Type-safe access to the fixture file path
- Share fixture files between test cases
- Cross-platform support
- Zero dependencies

Expand All @@ -32,7 +33,54 @@ However, this approach leads to the test code and fixture file definitions being

`@mizdra/inline-fixture-files` allows you to define fixture files in your test code. This makes the test code easier to understand.

```typescript
```ts
import dedent from 'dedent';
import { createIFF } from '@mizdra/inline-fixture-files';

const iff1 = await createIFF(
{
'src/index.ts': dedent`
export function hello() {
console.log('Hello, world!');
}
`,
},
{ rootDir: join(fixtureDir, 'test-case-1') },
);
const iff2 = await createIFF(
{
src: {
'index.ts': dedent`
import { add } from './math';
export function hello() {
console.log('Hello, world!');
console.log(add(1, 2));
}
`,
'math.ts': dedent`
export function add(a: number, b: number): number {
return a + b;
}
`,
},
},
{ rootDir: join(fixtureDir, 'test-case-1') },
);
```

## API documentation

See [/docs/api/index.md](/docs/api/index.md).

## Examples

### Example: Basic

You can use `iff.paths` to get the paths of the generated fixture files.

```ts
// example/01-basic.test.ts
import { rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
Expand Down Expand Up @@ -75,6 +123,124 @@ test('eslint reports lint errors', async () => {
});
```

## API documentation
### Example: Random `roodDir`

See [/docs/api/index.md](/docs/api/index.md).
If you use `@mizdra/inline-fixture-files`, it is recommended to create a utility (`createIFFByRandomRootDir`) that generates a random `rootDir` and calls `createIFF` with it. This is very helpful to keep each test case independent.

````ts
// example/util/create-iff-by-random-root-dir.js
import { randomUUID } from 'node:crypto';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { createIFF, Directory } from '@mizdra/inline-fixture-files';
/**
* The root directory for fixtures.
*
* NOTE: To avoid bloating `fixtureDir`, it is recommended to delete `fixtureDir` at the beginning of the test.
* ```ts
* // vitest.setup.ts
* import { rm } from 'node:fs/promises';
* await rm(fixtureDir, { recursive: true, force: true });
* ```
*/
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const fixtureDir = join(tmpdir(), 'inline-fs-fixtures', process.env['VITEST_POOL_ID']!);

export async function createIFFByRandomRootDir<const T extends Directory>(directory: T) {
const getRandomRootDir = () => join(fixtureDir, randomUUID());
const iff = await createIFF(directory, { rootDir: getRandomRootDir() });
return {
...iff,
fork: async function forkImpl<const U extends Directory>(additionalDirectory: U) {
const forkedIff = await iff.fork(additionalDirectory, { rootDir: getRandomRootDir() });
return { ...forkedIff, fork: forkImpl };
},
};
}
````

```ts
// example/02-random-root-dir.test.ts
import dedent from 'dedent';
import { ESLint } from 'eslint';
import { expect, test } from 'vitest';
import { createIFFByRandomRootDir } from './util/create-iff-by-random-root-dir.js';

test('eslint reports lint errors', async () => {
const iff = await createIFFByRandomRootDir({
'.eslintrc.cjs': `module.exports = { root: true, rules: { semi: 'error' } };`,
'src': {
'semi.js': dedent`
var withSemicolon = 1;
var withoutSemicolon = 2
`,
},
});

const eslint = new ESLint({ cwd: iff.rootDir, useEslintrc: true });
const results = await eslint.lintFiles([iff.paths['src/semi.js']]);
const formatter = await eslint.loadFormatter('unix');
const resultText = formatter.format(results);
expect(resultText).toStrictEqual(dedent`
${iff.paths['src/semi.js']}:2:25: Missing semicolon. [Error/semi]
1 problem
`);
});
```

### Example: Share fixture files between test cases

`iff.fork` is an API that changes the root directory while taking over previously created fixture files. It allows fixture files to be shared between test cases.

```ts
// example/03-share-fixtures-between-test-cases.test.ts
import { readFile } from 'node:fs/promises';
import dedent from 'dedent';
import { ESLint } from 'eslint';
import { describe, expect, it } from 'vitest';
import { createIFFByRandomRootDir } from './util/create-iff-by-random-root-dir.js';

describe('eslint', async () => {
// Share `.eslintrc.cjs` between test cases.
const baseIFF = await createIFFByRandomRootDir({
'.eslintrc.cjs': `module.exports = { root: true, rules: { semi: 'error' } };`,
});

it('reports lint errors', async () => {
// The `fork` allows you to change the `rootDir` of fixtures while inheriting the fixtures from `baseIFF`.
const iff = await baseIFF.fork({
src: {
'semi.js': dedent`
var withSemicolon = 1;
var withoutSemicolon = 2
`,
},
});
const eslint = new ESLint({ cwd: iff.rootDir, useEslintrc: true });
const results = await eslint.lintFiles([iff.paths['src/semi.js']]);
const formatter = await eslint.loadFormatter('unix');
const resultText = formatter.format(results);
expect(resultText).toStrictEqual(dedent`
${iff.paths['src/semi.js']}:2:25: Missing semicolon. [Error/semi]
1 problem
`);
});
it('fix lint errors', async () => {
const iff = await baseIFF.fork({
src: {
'semi.js': dedent`
var withoutSemicolon = 2
`,
},
});
const eslint = new ESLint({ cwd: iff.rootDir, useEslintrc: true, fix: true });
const results = await eslint.lintFiles([iff.paths['src/semi.js']]);

expect(await readFile(iff.paths['src/semi.js'], 'utf8')).toMatchInlineSnapshot('"var withoutSemicolon = 2"');
await ESLint.outputFixes(results);
expect(await readFile(iff.paths['src/semi.js'], 'utf8')).toMatchInlineSnapshot('"var withoutSemicolon = 2;"');
});
});
```
File renamed without changes.
26 changes: 26 additions & 0 deletions example/02-random-root-dir.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import dedent from 'dedent';
import { ESLint } from 'eslint';
import { expect, test } from 'vitest';
import { createIFFByRandomRootDir } from './util/create-iff-by-random-root-dir.js';

test('eslint reports lint errors', async () => {
const iff = await createIFFByRandomRootDir({
'.eslintrc.cjs': `module.exports = { root: true, rules: { semi: 'error' } };`,
'src': {
'semi.js': dedent`
var withSemicolon = 1;
var withoutSemicolon = 2
`,
},
});

const eslint = new ESLint({ cwd: iff.rootDir, useEslintrc: true });
const results = await eslint.lintFiles([iff.paths['src/semi.js']]);
const formatter = await eslint.loadFormatter('unix');
const resultText = formatter.format(results);
expect(resultText).toStrictEqual(dedent`
${iff.paths['src/semi.js']}:2:25: Missing semicolon. [Error/semi]
1 problem
`);
});
48 changes: 48 additions & 0 deletions example/03-share-fixtures-between-test-cases.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { readFile } from 'node:fs/promises';
import dedent from 'dedent';
import { ESLint } from 'eslint';
import { describe, expect, it } from 'vitest';
import { createIFFByRandomRootDir } from './util/create-iff-by-random-root-dir.js';

describe('eslint', async () => {
// Share `.eslintrc.cjs` between test cases.
const baseIFF = await createIFFByRandomRootDir({
'.eslintrc.cjs': `module.exports = { root: true, rules: { semi: 'error' } };`,
});

it('reports lint errors', async () => {
// The `fork` allows you to change the `rootDir` of fixtures while inheriting the fixtures from `baseIFF`.
const iff = await baseIFF.fork({
src: {
'semi.js': dedent`
var withSemicolon = 1;
var withoutSemicolon = 2
`,
},
});
const eslint = new ESLint({ cwd: iff.rootDir, useEslintrc: true });
const results = await eslint.lintFiles([iff.paths['src/semi.js']]);
const formatter = await eslint.loadFormatter('unix');
const resultText = formatter.format(results);
expect(resultText).toStrictEqual(dedent`
${iff.paths['src/semi.js']}:2:25: Missing semicolon. [Error/semi]
1 problem
`);
});
it('fix lint errors', async () => {
const iff = await baseIFF.fork({
src: {
'semi.js': dedent`
var withoutSemicolon = 2
`,
},
});
const eslint = new ESLint({ cwd: iff.rootDir, useEslintrc: true, fix: true });
const results = await eslint.lintFiles([iff.paths['src/semi.js']]);

expect(await readFile(iff.paths['src/semi.js'], 'utf8')).toMatchInlineSnapshot('"var withoutSemicolon = 2"');
await ESLint.outputFixes(results);
expect(await readFile(iff.paths['src/semi.js'], 'utf8')).toMatchInlineSnapshot('"var withoutSemicolon = 2;"');
});
});
28 changes: 28 additions & 0 deletions example/util/create-iff-by-random-root-dir.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { randomUUID } from 'node:crypto';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { createIFF, Directory } from '../../src/index.js';
/**
* The root directory for fixtures.
*
* NOTE: To avoid bloating `fixtureDir`, it is recommended to delete `fixtureDir` at the beginning of the test.
* ```ts
* // vitest.setup.ts
* import { rm } from 'node:fs/promises';
* await rm(fixtureDir, { recursive: true, force: true });
* ```
*/
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const fixtureDir = join(tmpdir(), 'inline-fs-fixtures', process.env['VITEST_POOL_ID']!);

export async function createIFFByRandomRootDir<const T extends Directory>(directory: T) {
const getRandomRootDir = () => join(fixtureDir, randomUUID());
const iff = await createIFF(directory, { rootDir: getRandomRootDir() });
return {
...iff,
fork: async function forkImpl<const U extends Directory>(additionalDirectory: U) {
const forkedIff = await iff.fork(additionalDirectory, { rootDir: getRandomRootDir() });
return { ...forkedIff, fork: forkImpl };
},
};
}

0 comments on commit 9d24578

Please sign in to comment.