├── .eslintignore
├── .eslintrc
├── .github
    ├── actions
    │   └── setup
    │   │   └── action.yml
    └── workflows
    │   └── ci.yml
├── .gitignore
├── .nvmrc
├── .prettierrc.json
├── .release-it.json
├── .yarn
    └── releases
    │   └── yarn-4.3.1.cjs
├── .yarnrc.yml
├── README.md
├── __fixtures__
    └── output.md
├── __tests__
    ├── __file_snapshots__
    │   ├── matches-binary-content-of-file-on-disk-0
    │   ├── matches-content-of-file-on-disk-with-file-extension-0.md
    │   ├── matches-content-of-file-on-disk-without-filename-0
    │   ├── works-with-.not-0
    │   ├── works-with-.not-for-binary-files-0
    │   └── works-with-non-binary-buffer-content-0
    ├── index.test.js
    └── minimal.pdf
├── commitlint.config.js
├── index.d.ts
├── index.js
├── lefthook.yml
├── package.json
├── tsconfig.json
└── yarn.lock
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | 
3 | 
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
 1 | {
 2 |   extends: "satya164",
 3 |   env: {
 4 |     node: true,
 5 |     jest: true,
 6 |   },
 7 |   rules: {
 8 |     'import/no-commonjs': 'off',
 9 |   }
10 | }
11 | 
--------------------------------------------------------------------------------
/.github/actions/setup/action.yml:
--------------------------------------------------------------------------------
 1 | name: Setup
 2 | description: Setup Node.js and install dependencies
 3 | 
 4 | runs:
 5 |   using: composite
 6 |   steps:
 7 |     - name: Setup Node.js
 8 |       uses: actions/setup-node@v3
 9 |       with:
10 |         node-version-file: .nvmrc
11 | 
12 |     - name: Cache dependencies
13 |       id: yarn-cache
14 |       uses: actions/cache@v3
15 |       with:
16 |         path: |
17 |           **/node_modules
18 |           .yarn/install-state.gz
19 |         key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}-${{ hashFiles('**/package.json', '!node_modules/**') }}
20 |         restore-keys: |
21 |           ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}
22 |           ${{ runner.os }}-yarn-
23 | 
24 |     - name: Install dependencies
25 |       if: steps.yarn-cache.outputs.cache-hit != 'true'
26 |       run: yarn install --immutable
27 |       shell: bash
28 | 
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
 1 | name: CI
 2 | on:
 3 |   push:
 4 |     branches:
 5 |       - main
 6 |   pull_request:
 7 |     branches:
 8 |       - main
 9 | 
10 | jobs:
11 |   lint:
12 |     runs-on: ubuntu-latest
13 |     steps:
14 |       - name: Checkout
15 |         uses: actions/checkout@v3
16 | 
17 |       - name: Setup
18 |         uses: ./.github/actions/setup
19 | 
20 |       - name: Lint files
21 |         run: yarn lint
22 | 
23 |       - name: Typecheck files
24 |         run: yarn typecheck
25 | 
26 |   test:
27 |     runs-on: ubuntu-latest
28 |     steps:
29 |       - name: Checkout
30 |         uses: actions/checkout@v3
31 | 
32 |       - name: Setup
33 |         uses: ./.github/actions/setup
34 | 
35 |       - name: Run unit tests
36 |         run: yarn test --maxWorkers=2 --coverage
37 | 
38 |       - name: Store test coverage
39 |         uses: actions/upload-artifact@v4
40 |         with:
41 |           name: coverage
42 |           path: coverage
43 | 
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
 1 | .DS_Store
 2 | .vscode
 3 | 
 4 | /node_modules/
 5 | 
 6 | 
 7 | # Yarn
 8 | .yarn/*
 9 | !.yarn/patches
10 | !.yarn/plugins
11 | !.yarn/releases
12 | !.yarn/sdks
13 | !.yarn/versions
14 | 
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | v20
2 | 
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 |   "singleQuote": true,
3 |   "tabWidth": 2,
4 |   "trailingComma": "es5",
5 |   "useTabs": false
6 | }
7 | 
--------------------------------------------------------------------------------
/.release-it.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "git": {
 3 |     "commitMessage": "chore: release ${version}",
 4 |     "tagName": "v${version}"
 5 |   },
 6 |   "npm": {
 7 |     "publish": true
 8 |   },
 9 |   "github": {
10 |     "release": true
11 |   },
12 |   "plugins": {
13 |     "@release-it/conventional-changelog": {
14 |       "preset": "angular"
15 |     }
16 |   }
17 | }
18 | 
--------------------------------------------------------------------------------
/.yarnrc.yml:
--------------------------------------------------------------------------------
1 | nodeLinker: node-modules
2 | 
3 | yarnPath: .yarn/releases/yarn-4.3.1.cjs
4 | 
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
 1 | # jest-file-snapshot
 2 | 
 3 | [![Build Status][build-badge]][build]
 4 | [![Code Coverage][coverage-badge]][coverage]
 5 | [![MIT License][license-badge]][license]
 6 | [![Version][version-badge]][package]
 7 | 
 8 | Jest matcher to write snapshots to a separate file instead of the default snapshot file used by Jest. Writing a snapshot to a separate file means you have proper syntax highlighting in the output file, and better readability without those pesky escape characters. It's also useful if you have binary content.
 9 | 
10 | ## Installation
11 | 
12 | ```sh
13 | npm install --save-dev jest-file-snapshot
14 | ```
15 | 
16 | or
17 | 
18 | ```sh
19 | yarn add --dev jest-file-snapshot
20 | ```
21 | 
22 | ## Usage
23 | 
24 | Extend Jest's `expect`:
25 | 
26 | ```js
27 | import { toMatchFile } from 'jest-file-snapshot';
28 | 
29 | expect.extend({ toMatchFile });
30 | ```
31 | 
32 | Then use it in your tests:
33 | 
34 | ```js
35 | it('matches content of file on disk', () => {
36 |   expect(content).toMatchFile();
37 | });
38 | ```
39 | 
40 | The content passed can be of type `string` or a `Buffer`. The comparison be done using `Buffer.equals()` instead of `===` if a `Buffer` is passed.
41 | 
42 | The matcher takes two optional arguments:
43 | 
44 | - `filepath`: path to the file whose content should be matched, e.g. `expect(content).toMatchFile(path.join(__dirname, 'output.md'))`
45 | - `options`: additional options object for the matcher, with following properties:
46 |   - `diff`: options for [`jest-diff`](https://github.com/facebook/jest/tree/master/packages/jest-diff)
47 |   - `fileExtension`: optional file extension to use for the snapshot file.
48 | 
49 | You should also [exclude the output files from Jest's watcher](https://jestjs.io/docs/en/configuration#watchpathignorepatterns-arraystring) so that updating the snapshot doesn't re-run the tests again.
50 | 
51 | For example, by default `toMatchFile` uses a folder named `__file_snapshots__` which you can exclude by adding the following under the `jest` key in `package.json`:
52 | 
53 | ```json
54 | "watchPathIgnorePatterns": [
55 |   "__file_snapshots__"
56 | ]
57 | ```
58 | 
59 | ## Credits
60 | 
61 | - [jest-image-snapshot](https://github.com/americanexpress/jest-image-snapshot)
62 | 
63 | ## Contributing
64 | 
65 | Make sure your code passes the unit tests, ESLint and TypeScript. Run the following to verify:
66 | 
67 | ```sh
68 | yarn test
69 | yarn lint
70 | yarn typescript
71 | ```
72 | 
73 | To fix formatting errors, run the following:
74 | 
75 | ```sh
76 | yarn lint -- --fix
77 | ```
78 | 
79 | 
80 | 
81 | [build-badge]: https://img.shields.io/circleci/project/github/satya164/jest-file-snapshot/main.svg?style=flat-square
82 | [build]: https://circleci.com/gh/satya164/jest-file-snapshot
83 | [coverage-badge]: https://img.shields.io/codecov/c/github/satya164/jest-file-snapshot.svg?style=flat-square
84 | [coverage]: https://codecov.io/github/satya164/jest-file-snapshot
85 | [license-badge]: https://img.shields.io/npm/l/jest-file-snapshot.svg?style=flat-square
86 | [license]: https://opensource.org/licenses/MIT
87 | [version-badge]: https://img.shields.io/npm/v/jest-file-snapshot.svg?style=flat-square
88 | [package]: https://www.npmjs.com/package/jest-file-snapshot
89 | 
--------------------------------------------------------------------------------
/__fixtures__/output.md:
--------------------------------------------------------------------------------
1 | # this is a test
--------------------------------------------------------------------------------
/__tests__/__file_snapshots__/matches-binary-content-of-file-on-disk-0:
--------------------------------------------------------------------------------
 1 | %PDF-1.1
 2 | %¥±ë
 3 | 
 4 | 1 0 obj
 5 |   << /Type /Catalog
 6 |      /Pages 2 0 R
 7 |   >>
 8 | endobj
 9 | 
10 | 2 0 obj
11 |   << /Type /Pages
12 |      /Kids [3 0 R]
13 |      /Count 1
14 |      /MediaBox [0 0 300 144]
15 |   >>
16 | endobj
17 | 
18 | 3 0 obj
19 |   <<  /Type /Page
20 |       /Parent 2 0 R
21 |       /Resources
22 |        << /Font
23 |            << /F1
24 |                << /Type /Font
25 |                   /Subtype /Type1
26 |                   /BaseFont /Times-Roman
27 |                >>
28 |            >>
29 |        >>
30 |       /Contents 4 0 R
31 |   >>
32 | endobj
33 | 
34 | 4 0 obj
35 |   << /Length 55 >>
36 | stream
37 |   BT
38 |     /F1 18 Tf
39 |     0 0 Td
40 |     (Hello World) Tj
41 |   ET
42 | endstream
43 | endobj
44 | 
45 | xref
46 | 0 5
47 | 0000000000 65535 f 
48 | 0000000018 00000 n 
49 | 0000000077 00000 n 
50 | 0000000178 00000 n 
51 | 0000000457 00000 n 
52 | trailer
53 |   <<  /Root 1 0 R
54 |       /Size 5
55 |   >>
56 | startxref
57 | 565
58 | %%EOF
59 | 
--------------------------------------------------------------------------------
/__tests__/__file_snapshots__/matches-content-of-file-on-disk-with-file-extension-0.md:
--------------------------------------------------------------------------------
1 | # this is a another test
--------------------------------------------------------------------------------
/__tests__/__file_snapshots__/matches-content-of-file-on-disk-without-filename-0:
--------------------------------------------------------------------------------
1 | # this is a another test
--------------------------------------------------------------------------------
/__tests__/__file_snapshots__/works-with-.not-0:
--------------------------------------------------------------------------------
1 | # this is a ugly test
2 | 
--------------------------------------------------------------------------------
/__tests__/__file_snapshots__/works-with-.not-for-binary-files-0:
--------------------------------------------------------------------------------
 1 | %PDF-1.1
 2 | %¥±ë
 3 | 
 4 | % MIT License
 5 | %
 6 | % Copyright (c) 2010 Brendan Zagaeski
 7 | %
 8 | % Permission is hereby granted, free of charge, to any person obtaining a copy
 9 | % of this software and associated documentation files (the "Software"), to deal
10 | % in the Software without restriction, including without limitation the rights
11 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | % copies of the Software, and to permit persons to whom the Software is
13 | % furnished to do so, subject to the following conditions:
14 | %
15 | % The above copyright notice and this permission notice shall be included in all
16 | % copies or substantial portions of the Software.
17 | %
18 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | % SOFTWARE.
25 | 
26 | 1 0 obj
27 |   << /Type /Catalog
28 |      /Pages 2 0 R
29 |   >>
30 | endobj
31 | 
32 | 2 0 obj
33 |   << /Type /Pages
34 |      /Kids [3 0 R]
35 |      /Count 1
36 |      /MediaBox [0 0 300 144]
37 |   >>
38 | endobj
39 | 
40 | 3 0 obj
41 |   <<  /Type /Page
42 |       /Parent 2 0 R
43 |       /Resources
44 |        << /Font
45 |            << /F1
46 |                << /Type /Font
47 |                   /Subtype /Type1
48 |                   /BaseFont /Times-Roman
49 |                >>
50 |            >>
51 |        >>
52 |       /Contents 4 0 R
53 |   >>
54 | endobj
55 | 
56 | 4 0 obj
57 |   << /Length 55 >>
58 | stream
59 |   BT
60 |     /F1 18 Tf
61 |     0 0 Td
62 |     (Hello World) Tj
63 |   ET
64 | endstream
65 | endobj
66 | 
67 | xref
68 | 0 5
69 | 0000000000 65535 f 
70 | 0000001130 00000 n 
71 | 0000001189 00000 n 
72 | 0000001290 00000 n 
73 | 0000001569 00000 n 
74 | trailer
75 |   <<  /Root 1 0 R
76 |       /Size 5
77 |   >>
78 | startxref
79 | 1677
80 | %%EOF
81 | 
--------------------------------------------------------------------------------
/__tests__/__file_snapshots__/works-with-non-binary-buffer-content-0:
--------------------------------------------------------------------------------
1 | # this is a buffer test
--------------------------------------------------------------------------------
/__tests__/index.test.js:
--------------------------------------------------------------------------------
 1 | const path = require('path');
 2 | const fs = require('fs');
 3 | const { toMatchFile } = require('../index');
 4 | 
 5 | expect.extend({ toMatchFile });
 6 | 
 7 | it('matches content of file on disk with specified filename', () => {
 8 |   expect(`# this is a test`).toMatchFile(
 9 |     path.join(__dirname, '..', '__fixtures__', 'output.md')
10 |   );
11 | });
12 | 
13 | it('matches content of file on disk without filename', () => {
14 |   expect(`# this is a another test`).toMatchFile();
15 | });
16 | 
17 | it('matches content of file on disk with file extension', () => {
18 |   expect(`# this is a another test`).toMatchFile(undefined, {
19 |     fileExtension: '.md',
20 |   });
21 | });
22 | 
23 | it('matches binary content of file on disk', () => {
24 |   expect(
25 |     fs.readFileSync(path.join(__dirname, 'minimal.pdf'), 'binary')
26 |   ).toMatchFile();
27 | });
28 | 
29 | it('works with non-binary buffer content', () => {
30 |   expect(Buffer.from('# this is a buffer test')).toMatchFile();
31 | });
32 | 
33 | it('works with .not', () => {
34 |   expect(`# this is a nice test`).not.toMatchFile();
35 | });
36 | 
37 | it('works with .not for binary files', () => {
38 |   expect(
39 |     fs.readFileSync(path.join(__dirname, 'minimal.pdf'), 'binary')
40 |   ).not.toMatchFile();
41 | });
42 | 
--------------------------------------------------------------------------------
/__tests__/minimal.pdf:
--------------------------------------------------------------------------------
 1 | %PDF-1.1
 2 | %¥±ë
 3 | 
 4 | 1 0 obj
 5 |   << /Type /Catalog
 6 |      /Pages 2 0 R
 7 |   >>
 8 | endobj
 9 | 
10 | 2 0 obj
11 |   << /Type /Pages
12 |      /Kids [3 0 R]
13 |      /Count 1
14 |      /MediaBox [0 0 300 144]
15 |   >>
16 | endobj
17 | 
18 | 3 0 obj
19 |   <<  /Type /Page
20 |       /Parent 2 0 R
21 |       /Resources
22 |        << /Font
23 |            << /F1
24 |                << /Type /Font
25 |                   /Subtype /Type1
26 |                   /BaseFont /Times-Roman
27 |                >>
28 |            >>
29 |        >>
30 |       /Contents 4 0 R
31 |   >>
32 | endobj
33 | 
34 | 4 0 obj
35 |   << /Length 55 >>
36 | stream
37 |   BT
38 |     /F1 18 Tf
39 |     0 0 Td
40 |     (Hello World) Tj
41 |   ET
42 | endstream
43 | endobj
44 | 
45 | xref
46 | 0 5
47 | 0000000000 65535 f 
48 | 0000000018 00000 n 
49 | 0000000077 00000 n 
50 | 0000000178 00000 n 
51 | 0000000457 00000 n 
52 | trailer
53 |   <<  /Root 1 0 R
54 |       /Size 5
55 |   >>
56 | startxref
57 | 565
58 | %%EOF
59 | 
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 |   extends: ['@commitlint/config-conventional'],
3 | };
4 | 
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
 1 | /// 
 2 | 
 3 | import { DiffOptions } from 'jest-diff';
 4 | 
 5 | export const toMatchFile: (
 6 |   content: string | Buffer,
 7 |   filename?: string,
 8 |   options?: FileMatcherOptions
 9 | ) => jest.CustomMatcherResult;
10 | 
11 | declare interface FileMatcherOptions {
12 |   diff?: DiffOptions;
13 |   fileExtension?: string;
14 | }
15 | 
16 | declare global {
17 |   namespace jest {
18 |     // eslint-disable-next-line @typescript-eslint/no-unused-vars
19 |     interface Matchers {
20 |       toMatchFile: (filename?: string, options?: FileMatcherOptions) => void;
21 |     }
22 | 
23 |     interface Expect {
24 |       toMatchFile: (filename?: string, options?: FileMatcherOptions) => void;
25 |     }
26 |   }
27 | }
28 | 
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
  1 | /* istanbul ignore file */
  2 | 
  3 | const fs = require('fs');
  4 | const path = require('path');
  5 | const chalk = require('chalk');
  6 | const { diff } = require('jest-diff');
  7 | const mkdirp = require('mkdirp');
  8 | const filenamify = require('filenamify');
  9 | 
 10 | /**
 11 |  * Check if 2 strings or buffer are equal
 12 |  * @param {string | Buffer} a
 13 |  * @param {string | Buffer} b
 14 |  */
 15 | const isEqual = (a, b) => {
 16 |   // @ts-ignore: TypeScript gives error if we pass string to buffer.equals
 17 |   return Buffer.isBuffer(a) ? a.equals(b) : a === b;
 18 | };
 19 | 
 20 | /**
 21 |  * Match given content against content of the specified file.
 22 |  *
 23 |  * @param {string | Buffer} content Output content to match
 24 |  * @param {string} [filepath] Path to the file to match against
 25 |  * @param {{
 26 |  *   diff?: import('jest-diff').DiffOptions,
 27 |  *   diffMethod?: (a: string, b: string, options: import('jest-diff').DiffOptions) => string,
 28 |  *   fileExtension?: string,
 29 |  * }} options
 30 |  * @this {{ testPath: string, currentTestName: string, assertionCalls: number, isNot: boolean, snapshotState: { added: number, updated: number, unmatched: number, _updateSnapshot: 'none' | 'new' | 'all' } }}
 31 |  */
 32 | exports.toMatchFile = function toMatchFile(content, filepath, options = {}) {
 33 |   const { isNot, snapshotState } = this;
 34 | 
 35 |   const fileExtension = options.fileExtension || '';
 36 | 
 37 |   const filename =
 38 |     filepath === undefined
 39 |       ? // If file name is not specified, generate one from the test title
 40 |         path.join(
 41 |           path.dirname(this.testPath),
 42 |           '__file_snapshots__',
 43 |           `${filenamify(
 44 |             this.currentTestName,
 45 |             {
 46 |               replacement: '-',
 47 |             },
 48 |             { maxLength: Infinity }
 49 |           ).replace(/\s/g, '-')}-${this.assertionCalls}`
 50 |         ) + fileExtension
 51 |       : filepath;
 52 | 
 53 |   options = {
 54 |     // Options for jest-diff
 55 |     diff: Object.assign(
 56 |       {
 57 |         expand: false,
 58 |         contextLines: 5,
 59 |         aAnnotation: 'Snapshot',
 60 |       },
 61 |       options.diff
 62 |     ),
 63 |   };
 64 | 
 65 |   if (snapshotState._updateSnapshot === 'none' && !fs.existsSync(filename)) {
 66 |     // We're probably running in CI environment
 67 | 
 68 |     snapshotState.unmatched++;
 69 | 
 70 |     return {
 71 |       pass: isNot,
 72 |       message: () =>
 73 |         `New output file ${chalk.blue(
 74 |           path.basename(filename)
 75 |         )} was ${chalk.bold.red('not written')}.\n\n` +
 76 |         'The update flag must be explicitly passed to write a new snapshot.\n\n' +
 77 |         `This is likely because this test is run in a ${chalk.blue(
 78 |           'continuous integration (CI) environment'
 79 |         )} in which snapshots are not written by default.\n\n`,
 80 |     };
 81 |   }
 82 | 
 83 |   if (fs.existsSync(filename)) {
 84 |     const output = fs.readFileSync(
 85 |       filename,
 86 |       Buffer.isBuffer(content) ? null : 'utf8'
 87 |     );
 88 | 
 89 |     if (isNot) {
 90 |       // The matcher is being used with `.not`
 91 | 
 92 |       if (!isEqual(content, output)) {
 93 |         // The value of `pass` is reversed when used with `.not`
 94 |         return { pass: false, message: () => '' };
 95 |       } else {
 96 |         snapshotState.unmatched++;
 97 | 
 98 |         return {
 99 |           pass: true,
100 |           message: () =>
101 |             `Expected received content ${chalk.red(
102 |               'to not match'
103 |             )} the file ${chalk.blue(path.basename(filename))}.`,
104 |         };
105 |       }
106 |     } else {
107 |       if (isEqual(content, output)) {
108 |         return { pass: true, message: () => '' };
109 |       } else {
110 |         if (snapshotState._updateSnapshot === 'all') {
111 |           mkdirp.sync(path.dirname(filename));
112 |           fs.writeFileSync(filename, content);
113 | 
114 |           snapshotState.updated++;
115 | 
116 |           return { pass: true, message: () => '' };
117 |         } else {
118 |           snapshotState.unmatched++;
119 | 
120 |           const diffMethod = options.diffMethod || diff;
121 |           const difference =
122 |             Buffer.isBuffer(content) || Buffer.isBuffer(output)
123 |               ? ''
124 |               : `\n\n${diffMethod(output, content, options.diff)}`;
125 | 
126 |           return {
127 |             pass: false,
128 |             message: () =>
129 |               `Received content ${chalk.red(
130 |                 "doesn't match"
131 |               )} the file ${chalk.blue(path.basename(filename))}.${difference}`,
132 |           };
133 |         }
134 |       }
135 |     }
136 |   } else {
137 |     if (
138 |       !isNot &&
139 |       (snapshotState._updateSnapshot === 'new' ||
140 |         snapshotState._updateSnapshot === 'all')
141 |     ) {
142 |       mkdirp.sync(path.dirname(filename));
143 |       fs.writeFileSync(filename, content);
144 | 
145 |       snapshotState.added++;
146 | 
147 |       return { pass: true, message: () => '' };
148 |     } else {
149 |       snapshotState.unmatched++;
150 | 
151 |       return {
152 |         pass: true,
153 |         message: () =>
154 |           `The output file ${chalk.blue(
155 |             path.basename(filename)
156 |           )} ${chalk.bold.red("doesn't exist")}.`,
157 |       };
158 |     }
159 |   }
160 | };
161 | 
--------------------------------------------------------------------------------
/lefthook.yml:
--------------------------------------------------------------------------------
 1 | pre-commit:
 2 |   parallel: true
 3 |   commands:
 4 |     lint:
 5 |       glob: "*.{js,ts,tsx}"
 6 |       run: yarn lint {staged_files}
 7 |     types:
 8 |       glob: "*.{json,js,ts,tsx}"
 9 |       run: yarn tsc --noEmit
10 |     test:
11 |       glob: "*.{json,js,ts,tsx}"
12 |       run: yarn test
13 | commit-msg:
14 |   parallel: true
15 |   commands:
16 |     commitlint:
17 |       run: yarn commitlint --edit
18 | 
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "jest-file-snapshot",
 3 |   "version": "0.7.0",
 4 |   "description": "Jest matcher to write snapshots to a separate file instead of the default snapshot file used by Jest",
 5 |   "keywords": [
 6 |     "test",
 7 |     "jest",
 8 |     "snapshot"
 9 |   ],
10 |   "main": "index.js",
11 |   "files": [
12 |     "index.js",
13 |     "index.d.ts"
14 |   ],
15 |   "types": "index.d.ts",
16 |   "license": "MIT",
17 |   "repository": {
18 |     "type": "git",
19 |     "url": "git+https://github.com/satya164/jest-file-snapshot.git"
20 |   },
21 |   "author": "Satyajit Sahoo  (https://github.com/satya164/)",
22 |   "scripts": {
23 |     "test": "jest",
24 |     "lint": "eslint .",
25 |     "typecheck": "tsc --noEmit",
26 |     "release": "release-it"
27 |   },
28 |   "publishConfig": {
29 |     "registry": "https://registry.npmjs.org/"
30 |   },
31 |   "devDependencies": {
32 |     "@babel/core": "^7.24.7",
33 |     "@commitlint/cli": "^19.3.0",
34 |     "@commitlint/config-conventional": "^19.2.2",
35 |     "@release-it/conventional-changelog": "^8.0.1",
36 |     "@types/jest": "^29.5.12",
37 |     "@types/jest-diff": "^24.3.0",
38 |     "@types/mkdirp": "^2.0.0",
39 |     "conventional-changelog-cli": "^5.0.0",
40 |     "eslint": "^8.56.0",
41 |     "eslint-config-satya164": "^3.2.1",
42 |     "jest": "^29.7.0",
43 |     "lefthook": "^1.7.0",
44 |     "prettier": "^3.3.2",
45 |     "release-it": "^17.4.1",
46 |     "typescript": "^5.5.3"
47 |   },
48 |   "dependencies": {
49 |     "chalk": "^4.1.2",
50 |     "filenamify": "^4.3.0",
51 |     "jest-diff": "^29.7.0",
52 |     "mkdirp": "^3.0.1"
53 |   },
54 |   "jest": {
55 |     "testEnvironment": "node",
56 |     "testMatch": [
57 |       "**/__tests__/**/*.test.js"
58 |     ],
59 |     "watchPathIgnorePatterns": [
60 |       "(__fixtures__|__file_snapshots__)"
61 |     ]
62 |   },
63 |   "packageManager": "yarn@4.3.1"
64 | }
65 | 
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "compilerOptions": {
 3 |     "allowUnreachableCode": false,
 4 |     "allowUnusedLabels": false,
 5 |     "esModuleInterop": true,
 6 |     "forceConsistentCasingInFileNames": true,
 7 |     "lib": ["esnext", "dom"],
 8 |     "module": "esnext",
 9 |     "moduleResolution": "node",
10 |     "noFallthroughCasesInSwitch": true,
11 |     "noImplicitReturns": true,
12 |     "noImplicitUseStrict": false,
13 |     "noStrictGenericChecks": false,
14 |     "noUnusedLocals": true,
15 |     "noUnusedParameters": true,
16 |     "resolveJsonModule": true,
17 |     "skipLibCheck": true,
18 |     "strict": true,
19 |     "target": "esnext",
20 |     "verbatimModuleSyntax": true
21 |   }
22 | }
23 | 
--------------------------------------------------------------------------------