Set up comprehensive frontend testing infrastructure
- Install Jest for unit testing with React Testing Library - Install Playwright for end-to-end testing - Configure Jest with proper TypeScript support and module mapping - Create test setup files and utilities for both unit and e2e tests Components: * Jest configuration with coverage thresholds * Playwright configuration with browser automation * Unit tests for LoginForm, AuthContext, and useSocketIO hook * E2E tests for authentication, dashboard, and agents workflows * GitHub Actions workflow for automated testing * Mock data and API utilities for consistent testing * Test documentation with best practices Testing features: - Unit tests with 70% coverage threshold - E2E tests with API mocking and user journey testing - CI/CD integration for automated test runs - Cross-browser testing support with Playwright - Authentication system testing end-to-end 🚀 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
22
frontend/node_modules/@jest/snapshot-utils/LICENSE
generated
vendored
Normal file
22
frontend/node_modules/@jest/snapshot-utils/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
Copyright Contributors to the Jest project.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
5
frontend/node_modules/@jest/snapshot-utils/api-extractor.json
generated
vendored
Normal file
5
frontend/node_modules/@jest/snapshot-utils/api-extractor.json
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "../../api-extractor.json",
|
||||
"mainEntryPointFilePath": "/Users/cpojer/Dropbox/Projects/jest/packages/jest-snapshot-utils/build/index.d.ts",
|
||||
"projectFolder": "/Users/cpojer/Dropbox/Projects/jest/packages/jest-snapshot-utils"
|
||||
}
|
||||
29
frontend/node_modules/@jest/snapshot-utils/build/index.d.mts
generated
vendored
Normal file
29
frontend/node_modules/@jest/snapshot-utils/build/index.d.mts
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Config } from "@jest/types";
|
||||
|
||||
//#region src/types.d.ts
|
||||
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
type SnapshotData = Record<string, string>;
|
||||
//#endregion
|
||||
//#region src/utils.d.ts
|
||||
|
||||
declare const SNAPSHOT_VERSION = "1";
|
||||
declare const SNAPSHOT_GUIDE_LINK = "https://jestjs.io/docs/snapshot-testing";
|
||||
declare const SNAPSHOT_VERSION_WARNING: string;
|
||||
declare const testNameToKey: (testName: string, count: number) => string;
|
||||
declare const keyToTestName: (key: string) => string;
|
||||
declare const getSnapshotData: (snapshotPath: string, update: Config.SnapshotUpdateState) => {
|
||||
data: SnapshotData;
|
||||
dirty: boolean;
|
||||
};
|
||||
declare const escapeBacktickString: (str: string) => string;
|
||||
declare const ensureDirectoryExists: (filePath: string) => void;
|
||||
declare const normalizeNewlines: (string: string) => string;
|
||||
declare const saveSnapshotFile: (snapshotData: SnapshotData, snapshotPath: string) => void;
|
||||
//#endregion
|
||||
export { SNAPSHOT_GUIDE_LINK, SNAPSHOT_VERSION, SNAPSHOT_VERSION_WARNING, SnapshotData, ensureDirectoryExists, escapeBacktickString, getSnapshotData, keyToTestName, normalizeNewlines, saveSnapshotFile, testNameToKey };
|
||||
42
frontend/node_modules/@jest/snapshot-utils/build/index.d.ts
generated
vendored
Normal file
42
frontend/node_modules/@jest/snapshot-utils/build/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {Config} from '@jest/types';
|
||||
|
||||
export declare const ensureDirectoryExists: (filePath: string) => void;
|
||||
|
||||
export declare const escapeBacktickString: (str: string) => string;
|
||||
|
||||
export declare const getSnapshotData: (
|
||||
snapshotPath: string,
|
||||
update: Config.SnapshotUpdateState,
|
||||
) => {
|
||||
data: SnapshotData;
|
||||
dirty: boolean;
|
||||
};
|
||||
|
||||
export declare const keyToTestName: (key: string) => string;
|
||||
|
||||
export declare const normalizeNewlines: (string: string) => string;
|
||||
|
||||
export declare const saveSnapshotFile: (
|
||||
snapshotData: SnapshotData,
|
||||
snapshotPath: string,
|
||||
) => void;
|
||||
|
||||
export declare const SNAPSHOT_GUIDE_LINK =
|
||||
'https://jestjs.io/docs/snapshot-testing';
|
||||
|
||||
export declare const SNAPSHOT_VERSION = '1';
|
||||
|
||||
export declare const SNAPSHOT_VERSION_WARNING: string;
|
||||
|
||||
export declare type SnapshotData = Record<string, string>;
|
||||
|
||||
export declare const testNameToKey: (testName: string, count: number) => string;
|
||||
|
||||
export {};
|
||||
221
frontend/node_modules/@jest/snapshot-utils/build/index.js
generated
vendored
Normal file
221
frontend/node_modules/@jest/snapshot-utils/build/index.js
generated
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
/*!
|
||||
* /**
|
||||
* * Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* *
|
||||
* * This source code is licensed under the MIT license found in the
|
||||
* * LICENSE file in the root directory of this source tree.
|
||||
* * /
|
||||
*/
|
||||
/******/ (() => { // webpackBootstrap
|
||||
/******/ "use strict";
|
||||
/******/ var __webpack_modules__ = ({
|
||||
|
||||
/***/ "./src/index.ts":
|
||||
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
||||
|
||||
|
||||
|
||||
Object.defineProperty(exports, "__esModule", ({
|
||||
value: true
|
||||
}));
|
||||
var _utils = __webpack_require__("./src/utils.ts");
|
||||
Object.keys(_utils).forEach(function (key) {
|
||||
if (key === "default" || key === "__esModule") return;
|
||||
if (key in exports && exports[key] === _utils[key]) return;
|
||||
Object.defineProperty(exports, key, {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _utils[key];
|
||||
}
|
||||
});
|
||||
});
|
||||
var _types = __webpack_require__("./src/types.ts");
|
||||
Object.keys(_types).forEach(function (key) {
|
||||
if (key === "default" || key === "__esModule") return;
|
||||
if (key in exports && exports[key] === _types[key]) return;
|
||||
Object.defineProperty(exports, key, {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _types[key];
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./src/types.ts":
|
||||
/***/ (() => {
|
||||
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./src/utils.ts":
|
||||
/***/ ((__unused_webpack_module, exports) => {
|
||||
|
||||
|
||||
|
||||
Object.defineProperty(exports, "__esModule", ({
|
||||
value: true
|
||||
}));
|
||||
exports.testNameToKey = exports.saveSnapshotFile = exports.normalizeNewlines = exports.keyToTestName = exports.getSnapshotData = exports.escapeBacktickString = exports.ensureDirectoryExists = exports.SNAPSHOT_VERSION_WARNING = exports.SNAPSHOT_VERSION = exports.SNAPSHOT_GUIDE_LINK = void 0;
|
||||
var path = _interopRequireWildcard(require("path"));
|
||||
var _chalk = _interopRequireDefault(require("chalk"));
|
||||
var fs = _interopRequireWildcard(require("graceful-fs"));
|
||||
var _naturalCompare = _interopRequireDefault(require("natural-compare"));
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
||||
var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol;
|
||||
var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol;
|
||||
var jestWriteFile = globalThis[Symbol.for('jest-native-write-file')] || fs.writeFileSync;
|
||||
var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol;
|
||||
var jestReadFile = globalThis[Symbol.for('jest-native-read-file')] || fs.readFileSync;
|
||||
var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol;
|
||||
var jestExistsFile = globalThis[Symbol.for('jest-native-exists-file')] || fs.existsSync;
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
const SNAPSHOT_VERSION = exports.SNAPSHOT_VERSION = '1';
|
||||
const SNAPSHOT_VERSION_REGEXP = /^\/\/ Jest Snapshot v(.+),/;
|
||||
const SNAPSHOT_GUIDE_LINK = exports.SNAPSHOT_GUIDE_LINK = 'https://jestjs.io/docs/snapshot-testing';
|
||||
const SNAPSHOT_VERSION_WARNING = exports.SNAPSHOT_VERSION_WARNING = _chalk.default.yellow(`${_chalk.default.bold('Warning')}: Before you upgrade snapshots, ` + 'we recommend that you revert any local changes to tests or other code, ' + 'to ensure that you do not store invalid state.');
|
||||
const writeSnapshotVersion = () => `// Jest Snapshot v${SNAPSHOT_VERSION}, ${SNAPSHOT_GUIDE_LINK}`;
|
||||
const validateSnapshotVersion = snapshotContents => {
|
||||
const versionTest = SNAPSHOT_VERSION_REGEXP.exec(snapshotContents);
|
||||
const version = versionTest && versionTest[1];
|
||||
if (!version) {
|
||||
return new Error(_chalk.default.red(`${_chalk.default.bold('Outdated snapshot')}: No snapshot header found. ` + 'Jest 19 introduced versioned snapshots to ensure all developers ' + 'on a project are using the same version of Jest. ' + 'Please update all snapshots during this upgrade of Jest.\n\n') + SNAPSHOT_VERSION_WARNING);
|
||||
}
|
||||
if (version < SNAPSHOT_VERSION) {
|
||||
return new Error(
|
||||
// eslint-disable-next-line prefer-template
|
||||
_chalk.default.red(`${_chalk.default.red.bold('Outdated snapshot')}: The version of the snapshot ` + 'file associated with this test is outdated. The snapshot file ' + 'version ensures that all developers on a project are using ' + 'the same version of Jest. ' + 'Please update all snapshots during this upgrade of Jest.') + '\n\n' + `Expected: v${SNAPSHOT_VERSION}\n` + `Received: v${version}\n\n` + SNAPSHOT_VERSION_WARNING);
|
||||
}
|
||||
if (version > SNAPSHOT_VERSION) {
|
||||
return new Error(
|
||||
// eslint-disable-next-line prefer-template
|
||||
_chalk.default.red(`${_chalk.default.red.bold('Outdated Jest version')}: The version of this ` + 'snapshot file indicates that this project is meant to be used ' + 'with a newer version of Jest. The snapshot file version ensures ' + 'that all developers on a project are using the same version of ' + 'Jest. Please update your version of Jest and re-run the tests.') + '\n\n' + `Expected: v${SNAPSHOT_VERSION}\n` + `Received: v${version}`);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
const normalizeTestNameForKey = testName => testName.replaceAll(/\r\n|\r|\n/g, match => {
|
||||
switch (match) {
|
||||
case '\r\n':
|
||||
return '\\r\\n';
|
||||
case '\r':
|
||||
return '\\r';
|
||||
case '\n':
|
||||
return '\\n';
|
||||
default:
|
||||
return match;
|
||||
}
|
||||
});
|
||||
const denormalizeTestNameFromKey = key => key.replaceAll(/\\r\\n|\\r|\\n/g, match => {
|
||||
switch (match) {
|
||||
case '\\r\\n':
|
||||
return '\r\n';
|
||||
case '\\r':
|
||||
return '\r';
|
||||
case '\\n':
|
||||
return '\n';
|
||||
default:
|
||||
return match;
|
||||
}
|
||||
});
|
||||
const testNameToKey = (testName, count) => `${normalizeTestNameForKey(testName)} ${count}`;
|
||||
exports.testNameToKey = testNameToKey;
|
||||
const keyToTestName = key => {
|
||||
if (!/ \d+$/.test(key)) {
|
||||
throw new Error('Snapshot keys must end with a number.');
|
||||
}
|
||||
const testNameWithoutCount = key.replace(/ \d+$/, '');
|
||||
return denormalizeTestNameFromKey(testNameWithoutCount);
|
||||
};
|
||||
exports.keyToTestName = keyToTestName;
|
||||
const getSnapshotData = (snapshotPath, update) => {
|
||||
const data = Object.create(null);
|
||||
let snapshotContents = '';
|
||||
let dirty = false;
|
||||
if (jestExistsFile(snapshotPath)) {
|
||||
try {
|
||||
snapshotContents = jestReadFile(snapshotPath, 'utf8');
|
||||
// eslint-disable-next-line no-new-func
|
||||
const populate = new Function('exports', snapshotContents);
|
||||
populate(data);
|
||||
} catch {}
|
||||
}
|
||||
const validationResult = validateSnapshotVersion(snapshotContents);
|
||||
const isInvalid = snapshotContents && validationResult;
|
||||
if (update === 'none' && isInvalid) {
|
||||
throw validationResult;
|
||||
}
|
||||
if ((update === 'all' || update === 'new') && isInvalid) {
|
||||
dirty = true;
|
||||
}
|
||||
return {
|
||||
data,
|
||||
dirty
|
||||
};
|
||||
};
|
||||
exports.getSnapshotData = getSnapshotData;
|
||||
const escapeBacktickString = str => str.replaceAll(/`|\\|\${/g, '\\$&');
|
||||
exports.escapeBacktickString = escapeBacktickString;
|
||||
const printBacktickString = str => `\`${escapeBacktickString(str)}\``;
|
||||
const ensureDirectoryExists = filePath => {
|
||||
try {
|
||||
fs.mkdirSync(path.dirname(filePath), {
|
||||
recursive: true
|
||||
});
|
||||
} catch {}
|
||||
};
|
||||
exports.ensureDirectoryExists = ensureDirectoryExists;
|
||||
const normalizeNewlines = string => string.replaceAll(/\r\n|\r/g, '\n');
|
||||
exports.normalizeNewlines = normalizeNewlines;
|
||||
const saveSnapshotFile = (snapshotData, snapshotPath) => {
|
||||
const snapshots = Object.keys(snapshotData).sort(_naturalCompare.default).map(key => `exports[${printBacktickString(key)}] = ${printBacktickString(normalizeNewlines(snapshotData[key]))};`);
|
||||
ensureDirectoryExists(snapshotPath);
|
||||
jestWriteFile(snapshotPath, `${writeSnapshotVersion()}\n\n${snapshots.join('\n\n')}\n`);
|
||||
};
|
||||
exports.saveSnapshotFile = saveSnapshotFile;
|
||||
|
||||
/***/ })
|
||||
|
||||
/******/ });
|
||||
/************************************************************************/
|
||||
/******/ // The module cache
|
||||
/******/ var __webpack_module_cache__ = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/ // Check if module is in cache
|
||||
/******/ var cachedModule = __webpack_module_cache__[moduleId];
|
||||
/******/ if (cachedModule !== undefined) {
|
||||
/******/ return cachedModule.exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = __webpack_module_cache__[moduleId] = {
|
||||
/******/ // no module.id needed
|
||||
/******/ // no module.loaded needed
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/************************************************************************/
|
||||
/******/
|
||||
/******/ // startup
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ // This entry module is referenced by other modules so it can't be inlined
|
||||
/******/ var __webpack_exports__ = __webpack_require__("./src/index.ts");
|
||||
/******/ module.exports = __webpack_exports__;
|
||||
/******/
|
||||
/******/ })()
|
||||
;
|
||||
12
frontend/node_modules/@jest/snapshot-utils/build/index.mjs
generated
vendored
Normal file
12
frontend/node_modules/@jest/snapshot-utils/build/index.mjs
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import cjsModule from './index.js';
|
||||
|
||||
export const SNAPSHOT_GUIDE_LINK = cjsModule.SNAPSHOT_GUIDE_LINK;
|
||||
export const SNAPSHOT_VERSION = cjsModule.SNAPSHOT_VERSION;
|
||||
export const SNAPSHOT_VERSION_WARNING = cjsModule.SNAPSHOT_VERSION_WARNING;
|
||||
export const ensureDirectoryExists = cjsModule.ensureDirectoryExists;
|
||||
export const escapeBacktickString = cjsModule.escapeBacktickString;
|
||||
export const getSnapshotData = cjsModule.getSnapshotData;
|
||||
export const keyToTestName = cjsModule.keyToTestName;
|
||||
export const normalizeNewlines = cjsModule.normalizeNewlines;
|
||||
export const saveSnapshotFile = cjsModule.saveSnapshotFile;
|
||||
export const testNameToKey = cjsModule.testNameToKey;
|
||||
38
frontend/node_modules/@jest/snapshot-utils/package.json
generated
vendored
Normal file
38
frontend/node_modules/@jest/snapshot-utils/package.json
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "@jest/snapshot-utils",
|
||||
"version": "30.0.4",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jestjs/jest.git",
|
||||
"directory": "packages/jest-snapshot-utils"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "./build/index.js",
|
||||
"types": "./build/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./build/index.d.ts",
|
||||
"require": "./build/index.js",
|
||||
"import": "./build/index.mjs",
|
||||
"default": "./build/index.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jest/types": "30.0.1",
|
||||
"chalk": "^4.1.2",
|
||||
"graceful-fs": "^4.2.11",
|
||||
"natural-compare": "^1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/graceful-fs": "^4.1.9",
|
||||
"@types/natural-compare": "^1.4.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"gitHead": "f4296d2bc85c1405f84ddf613a25d0bc3766b7e5"
|
||||
}
|
||||
211
frontend/node_modules/@jest/snapshot-utils/src/__tests__/utils.test.ts
generated
vendored
Normal file
211
frontend/node_modules/@jest/snapshot-utils/src/__tests__/utils.test.ts
generated
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
jest.mock('graceful-fs', () => ({
|
||||
...jest.createMockFromModule<typeof import('fs')>('fs'),
|
||||
existsSync: jest.fn().mockReturnValue(true),
|
||||
}));
|
||||
|
||||
import * as path from 'path';
|
||||
import chalk from 'chalk';
|
||||
import * as fs from 'graceful-fs';
|
||||
import {
|
||||
SNAPSHOT_GUIDE_LINK,
|
||||
SNAPSHOT_VERSION,
|
||||
SNAPSHOT_VERSION_WARNING,
|
||||
getSnapshotData,
|
||||
keyToTestName,
|
||||
saveSnapshotFile,
|
||||
testNameToKey,
|
||||
} from '../utils';
|
||||
|
||||
test('keyToTestName()', () => {
|
||||
expect(keyToTestName('abc cde 12')).toBe('abc cde');
|
||||
expect(keyToTestName('abc cde 12')).toBe('abc cde ');
|
||||
expect(keyToTestName('test with\\r\\nCRLF 1')).toBe('test with\r\nCRLF');
|
||||
expect(keyToTestName('test with\\rCR 1')).toBe('test with\rCR');
|
||||
expect(keyToTestName('test with\\nLF 1')).toBe('test with\nLF');
|
||||
expect(() => keyToTestName('abc cde')).toThrow(
|
||||
'Snapshot keys must end with a number.',
|
||||
);
|
||||
});
|
||||
|
||||
test('testNameToKey', () => {
|
||||
expect(testNameToKey('abc cde', 1)).toBe('abc cde 1');
|
||||
expect(testNameToKey('abc cde ', 12)).toBe('abc cde 12');
|
||||
});
|
||||
|
||||
test('testNameToKey escapes line endings to prevent collisions', () => {
|
||||
expect(testNameToKey('test with\r\nCRLF', 1)).toBe('test with\\r\\nCRLF 1');
|
||||
expect(testNameToKey('test with\rCR', 1)).toBe('test with\\rCR 1');
|
||||
expect(testNameToKey('test with\nLF', 1)).toBe('test with\\nLF 1');
|
||||
|
||||
expect(testNameToKey('test\r\n', 1)).not.toBe(testNameToKey('test\r', 1));
|
||||
expect(testNameToKey('test\r\n', 1)).not.toBe(testNameToKey('test\n', 1));
|
||||
expect(testNameToKey('test\r', 1)).not.toBe(testNameToKey('test\n', 1));
|
||||
});
|
||||
|
||||
test('keyToTestName reverses testNameToKey transformation', () => {
|
||||
const testCases = [
|
||||
'simple test',
|
||||
'test with\r\nCRLF',
|
||||
'test with\rCR only',
|
||||
'test with\nLF only',
|
||||
'mixed\r\nline\rendings\n',
|
||||
'test\r',
|
||||
'test\r\n',
|
||||
'test\n',
|
||||
];
|
||||
|
||||
for (const testName of testCases) {
|
||||
const key = testNameToKey(testName, 1);
|
||||
const recovered = keyToTestName(key);
|
||||
expect(recovered).toBe(testName);
|
||||
}
|
||||
});
|
||||
|
||||
test('saveSnapshotFile() works with \r\n', () => {
|
||||
const filename = path.join(__dirname, 'remove-newlines.snap');
|
||||
const data = {
|
||||
myKey: '<div>\r\n</div>',
|
||||
};
|
||||
|
||||
saveSnapshotFile(data, filename);
|
||||
expect(fs.writeFileSync).toHaveBeenCalledWith(
|
||||
filename,
|
||||
`// Jest Snapshot v1, ${SNAPSHOT_GUIDE_LINK}\n\n` +
|
||||
'exports[`myKey`] = `<div>\n</div>`;\n',
|
||||
);
|
||||
});
|
||||
|
||||
test('saveSnapshotFile() works with \r', () => {
|
||||
const filename = path.join(__dirname, 'remove-newlines.snap');
|
||||
const data = {
|
||||
myKey: '<div>\r</div>',
|
||||
};
|
||||
|
||||
saveSnapshotFile(data, filename);
|
||||
expect(fs.writeFileSync).toHaveBeenCalledWith(
|
||||
filename,
|
||||
`// Jest Snapshot v1, ${SNAPSHOT_GUIDE_LINK}\n\n` +
|
||||
'exports[`myKey`] = `<div>\n</div>`;\n',
|
||||
);
|
||||
});
|
||||
|
||||
test('getSnapshotData() throws when no snapshot version', () => {
|
||||
const filename = path.join(__dirname, 'old-snapshot.snap');
|
||||
jest
|
||||
.mocked(fs.readFileSync)
|
||||
.mockReturnValue('exports[`myKey`] = `<div>\n</div>`;\n');
|
||||
const update = 'none';
|
||||
|
||||
expect(() => getSnapshotData(filename, update)).toThrow(
|
||||
chalk.red(
|
||||
`${chalk.bold('Outdated snapshot')}: No snapshot header found. ` +
|
||||
'Jest 19 introduced versioned snapshots to ensure all developers on ' +
|
||||
'a project are using the same version of Jest. ' +
|
||||
'Please update all snapshots during this upgrade of Jest.\n\n',
|
||||
) + SNAPSHOT_VERSION_WARNING,
|
||||
);
|
||||
});
|
||||
|
||||
test('getSnapshotData() throws for older snapshot version', () => {
|
||||
const filename = path.join(__dirname, 'old-snapshot.snap');
|
||||
jest
|
||||
.mocked(fs.readFileSync)
|
||||
.mockReturnValue(
|
||||
`// Jest Snapshot v0.99, ${SNAPSHOT_GUIDE_LINK}\n\n` +
|
||||
'exports[`myKey`] = `<div>\n</div>`;\n',
|
||||
);
|
||||
const update = 'none';
|
||||
|
||||
expect(() => getSnapshotData(filename, update)).toThrow(
|
||||
`${chalk.red(
|
||||
`${chalk.red.bold('Outdated snapshot')}: The version of the snapshot ` +
|
||||
'file associated with this test is outdated. The snapshot file ' +
|
||||
'version ensures that all developers on a project are using ' +
|
||||
'the same version of Jest. ' +
|
||||
'Please update all snapshots during this upgrade of Jest.',
|
||||
)}\n\nExpected: v${SNAPSHOT_VERSION}\n` +
|
||||
`Received: v0.99\n\n${SNAPSHOT_VERSION_WARNING}`,
|
||||
);
|
||||
});
|
||||
|
||||
test('getSnapshotData() throws for newer snapshot version', () => {
|
||||
const filename = path.join(__dirname, 'old-snapshot.snap');
|
||||
jest
|
||||
.mocked(fs.readFileSync)
|
||||
.mockReturnValue(
|
||||
`// Jest Snapshot v2, ${SNAPSHOT_GUIDE_LINK}\n\n` +
|
||||
'exports[`myKey`] = `<div>\n</div>`;\n',
|
||||
);
|
||||
const update = 'none';
|
||||
|
||||
expect(() => getSnapshotData(filename, update)).toThrow(
|
||||
`${chalk.red(
|
||||
`${chalk.red.bold('Outdated Jest version')}: The version of this ` +
|
||||
'snapshot file indicates that this project is meant to be used ' +
|
||||
'with a newer version of Jest. ' +
|
||||
'The snapshot file version ensures that all developers on a project ' +
|
||||
'are using the same version of Jest. ' +
|
||||
'Please update your version of Jest and re-run the tests.',
|
||||
)}\n\nExpected: v${SNAPSHOT_VERSION}\nReceived: v2`,
|
||||
);
|
||||
});
|
||||
|
||||
test('getSnapshotData() does not throw for when updating', () => {
|
||||
const filename = path.join(__dirname, 'old-snapshot.snap');
|
||||
jest
|
||||
.mocked(fs.readFileSync)
|
||||
.mockReturnValue('exports[`myKey`] = `<div>\n</div>`;\n');
|
||||
const update = 'all';
|
||||
|
||||
expect(() => getSnapshotData(filename, update)).not.toThrow();
|
||||
});
|
||||
|
||||
test('getSnapshotData() marks invalid snapshot dirty when updating', () => {
|
||||
const filename = path.join(__dirname, 'old-snapshot.snap');
|
||||
jest
|
||||
.mocked(fs.readFileSync)
|
||||
.mockReturnValue('exports[`myKey`] = `<div>\n</div>`;\n');
|
||||
const update = 'all';
|
||||
|
||||
expect(getSnapshotData(filename, update)).toMatchObject({dirty: true});
|
||||
});
|
||||
|
||||
test('getSnapshotData() marks valid snapshot not dirty when updating', () => {
|
||||
const filename = path.join(__dirname, 'old-snapshot.snap');
|
||||
jest
|
||||
.mocked(fs.readFileSync)
|
||||
.mockReturnValue(
|
||||
`// Jest Snapshot v${SNAPSHOT_VERSION}, ${SNAPSHOT_GUIDE_LINK}\n\n` +
|
||||
'exports[`myKey`] = `<div>\n</div>`;\n',
|
||||
);
|
||||
const update = 'all';
|
||||
|
||||
expect(getSnapshotData(filename, update)).toMatchObject({dirty: false});
|
||||
});
|
||||
|
||||
test('escaping', () => {
|
||||
const filename = path.join(__dirname, 'escaping.snap');
|
||||
const data = '"\'\\';
|
||||
const writeFileSync = jest.mocked(fs.writeFileSync);
|
||||
|
||||
writeFileSync.mockReset();
|
||||
saveSnapshotFile({key: data}, filename);
|
||||
const writtenData = writeFileSync.mock.calls[0][1];
|
||||
expect(writtenData).toBe(
|
||||
`// Jest Snapshot v1, ${SNAPSHOT_GUIDE_LINK}\n\n` +
|
||||
'exports[`key`] = `"\'\\\\`;\n',
|
||||
);
|
||||
|
||||
// eslint-disable-next-line no-eval
|
||||
const readData = eval(`var exports = {}; ${writtenData} exports`);
|
||||
expect(readData).toEqual({key: data});
|
||||
const snapshotData = readData.key;
|
||||
expect(data).toEqual(snapshotData);
|
||||
});
|
||||
9
frontend/node_modules/@jest/snapshot-utils/src/index.ts
generated
vendored
Normal file
9
frontend/node_modules/@jest/snapshot-utils/src/index.ts
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
export * from './utils';
|
||||
export * from './types';
|
||||
8
frontend/node_modules/@jest/snapshot-utils/src/types.ts
generated
vendored
Normal file
8
frontend/node_modules/@jest/snapshot-utils/src/types.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
export type SnapshotData = Record<string, string>;
|
||||
184
frontend/node_modules/@jest/snapshot-utils/src/utils.ts
generated
vendored
Normal file
184
frontend/node_modules/@jest/snapshot-utils/src/utils.ts
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import * as path from 'path';
|
||||
import chalk from 'chalk';
|
||||
import * as fs from 'graceful-fs';
|
||||
import naturalCompare from 'natural-compare';
|
||||
import type {Config} from '@jest/types';
|
||||
import type {SnapshotData} from './types';
|
||||
|
||||
export const SNAPSHOT_VERSION = '1';
|
||||
const SNAPSHOT_VERSION_REGEXP = /^\/\/ Jest Snapshot v(.+),/;
|
||||
export const SNAPSHOT_GUIDE_LINK = 'https://jestjs.io/docs/snapshot-testing';
|
||||
export const SNAPSHOT_VERSION_WARNING = chalk.yellow(
|
||||
`${chalk.bold('Warning')}: Before you upgrade snapshots, ` +
|
||||
'we recommend that you revert any local changes to tests or other code, ' +
|
||||
'to ensure that you do not store invalid state.',
|
||||
);
|
||||
|
||||
const writeSnapshotVersion = () =>
|
||||
`// Jest Snapshot v${SNAPSHOT_VERSION}, ${SNAPSHOT_GUIDE_LINK}`;
|
||||
|
||||
const validateSnapshotVersion = (snapshotContents: string) => {
|
||||
const versionTest = SNAPSHOT_VERSION_REGEXP.exec(snapshotContents);
|
||||
const version = versionTest && versionTest[1];
|
||||
|
||||
if (!version) {
|
||||
return new Error(
|
||||
chalk.red(
|
||||
`${chalk.bold('Outdated snapshot')}: No snapshot header found. ` +
|
||||
'Jest 19 introduced versioned snapshots to ensure all developers ' +
|
||||
'on a project are using the same version of Jest. ' +
|
||||
'Please update all snapshots during this upgrade of Jest.\n\n',
|
||||
) + SNAPSHOT_VERSION_WARNING,
|
||||
);
|
||||
}
|
||||
|
||||
if (version < SNAPSHOT_VERSION) {
|
||||
return new Error(
|
||||
// eslint-disable-next-line prefer-template
|
||||
chalk.red(
|
||||
`${chalk.red.bold('Outdated snapshot')}: The version of the snapshot ` +
|
||||
'file associated with this test is outdated. The snapshot file ' +
|
||||
'version ensures that all developers on a project are using ' +
|
||||
'the same version of Jest. ' +
|
||||
'Please update all snapshots during this upgrade of Jest.',
|
||||
) +
|
||||
'\n\n' +
|
||||
`Expected: v${SNAPSHOT_VERSION}\n` +
|
||||
`Received: v${version}\n\n` +
|
||||
SNAPSHOT_VERSION_WARNING,
|
||||
);
|
||||
}
|
||||
|
||||
if (version > SNAPSHOT_VERSION) {
|
||||
return new Error(
|
||||
// eslint-disable-next-line prefer-template
|
||||
chalk.red(
|
||||
`${chalk.red.bold('Outdated Jest version')}: The version of this ` +
|
||||
'snapshot file indicates that this project is meant to be used ' +
|
||||
'with a newer version of Jest. The snapshot file version ensures ' +
|
||||
'that all developers on a project are using the same version of ' +
|
||||
'Jest. Please update your version of Jest and re-run the tests.',
|
||||
) +
|
||||
'\n\n' +
|
||||
`Expected: v${SNAPSHOT_VERSION}\n` +
|
||||
`Received: v${version}`,
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const normalizeTestNameForKey = (testName: string): string =>
|
||||
testName.replaceAll(/\r\n|\r|\n/g, match => {
|
||||
switch (match) {
|
||||
case '\r\n':
|
||||
return '\\r\\n';
|
||||
case '\r':
|
||||
return '\\r';
|
||||
case '\n':
|
||||
return '\\n';
|
||||
default:
|
||||
return match;
|
||||
}
|
||||
});
|
||||
|
||||
const denormalizeTestNameFromKey = (key: string): string =>
|
||||
key.replaceAll(/\\r\\n|\\r|\\n/g, match => {
|
||||
switch (match) {
|
||||
case '\\r\\n':
|
||||
return '\r\n';
|
||||
case '\\r':
|
||||
return '\r';
|
||||
case '\\n':
|
||||
return '\n';
|
||||
default:
|
||||
return match;
|
||||
}
|
||||
});
|
||||
|
||||
export const testNameToKey = (testName: string, count: number): string =>
|
||||
`${normalizeTestNameForKey(testName)} ${count}`;
|
||||
|
||||
export const keyToTestName = (key: string): string => {
|
||||
if (!/ \d+$/.test(key)) {
|
||||
throw new Error('Snapshot keys must end with a number.');
|
||||
}
|
||||
const testNameWithoutCount = key.replace(/ \d+$/, '');
|
||||
return denormalizeTestNameFromKey(testNameWithoutCount);
|
||||
};
|
||||
|
||||
export const getSnapshotData = (
|
||||
snapshotPath: string,
|
||||
update: Config.SnapshotUpdateState,
|
||||
): {
|
||||
data: SnapshotData;
|
||||
dirty: boolean;
|
||||
} => {
|
||||
const data = Object.create(null);
|
||||
let snapshotContents = '';
|
||||
let dirty = false;
|
||||
|
||||
if (fs.existsSync(snapshotPath)) {
|
||||
try {
|
||||
snapshotContents = fs.readFileSync(snapshotPath, 'utf8');
|
||||
// eslint-disable-next-line no-new-func
|
||||
const populate = new Function('exports', snapshotContents);
|
||||
populate(data);
|
||||
} catch {}
|
||||
}
|
||||
|
||||
const validationResult = validateSnapshotVersion(snapshotContents);
|
||||
const isInvalid = snapshotContents && validationResult;
|
||||
|
||||
if (update === 'none' && isInvalid) {
|
||||
throw validationResult;
|
||||
}
|
||||
|
||||
if ((update === 'all' || update === 'new') && isInvalid) {
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
return {data, dirty};
|
||||
};
|
||||
|
||||
export const escapeBacktickString = (str: string): string =>
|
||||
str.replaceAll(/`|\\|\${/g, '\\$&');
|
||||
|
||||
const printBacktickString = (str: string): string =>
|
||||
`\`${escapeBacktickString(str)}\``;
|
||||
|
||||
export const ensureDirectoryExists = (filePath: string): void => {
|
||||
try {
|
||||
fs.mkdirSync(path.dirname(filePath), {recursive: true});
|
||||
} catch {}
|
||||
};
|
||||
|
||||
export const normalizeNewlines = (string: string): string =>
|
||||
string.replaceAll(/\r\n|\r/g, '\n');
|
||||
|
||||
export const saveSnapshotFile = (
|
||||
snapshotData: SnapshotData,
|
||||
snapshotPath: string,
|
||||
): void => {
|
||||
const snapshots = Object.keys(snapshotData)
|
||||
.sort(naturalCompare)
|
||||
.map(
|
||||
key =>
|
||||
`exports[${printBacktickString(key)}] = ${printBacktickString(
|
||||
normalizeNewlines(snapshotData[key]),
|
||||
)};`,
|
||||
);
|
||||
|
||||
ensureDirectoryExists(snapshotPath);
|
||||
fs.writeFileSync(
|
||||
snapshotPath,
|
||||
`${writeSnapshotVersion()}\n\n${snapshots.join('\n\n')}\n`,
|
||||
);
|
||||
};
|
||||
10
frontend/node_modules/@jest/snapshot-utils/tsconfig.json
generated
vendored
Normal file
10
frontend/node_modules/@jest/snapshot-utils/tsconfig.json
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "build"
|
||||
},
|
||||
"include": ["./src/**/*"],
|
||||
"exclude": ["./**/__mocks__/**/*", "./**/__tests__/**/*"],
|
||||
"references": [{"path": "../jest-types"}]
|
||||
}
|
||||
Reference in New Issue
Block a user