2021-12-02 10:19:32 +08:00
|
|
|
|
import fs from "node:fs";
|
|
|
|
|
|
import path from "node:path";
|
|
|
|
|
|
import createEsmUtils from "esm-utils";
|
|
|
|
|
|
import { projectRoot } from "../env.js";
|
2023-12-17 19:34:12 +00:00
|
|
|
|
import jestPathSerializer from "../path-serializer.js";
|
2020-03-17 01:34:32 +02:00
|
|
|
|
|
2021-12-02 10:19:32 +08:00
|
|
|
|
const { __dirname } = createEsmUtils(import.meta);
|
2020-03-17 01:34:32 +02:00
|
|
|
|
|
2021-12-02 10:19:32 +08:00
|
|
|
|
expect.addSnapshotSerializer(jestPathSerializer);
|
2020-03-17 01:34:32 +02:00
|
|
|
|
|
2023-05-04 17:20:05 +08:00
|
|
|
|
const runCliWithoutGitignore = (dir, args, options) =>
|
|
|
|
|
|
runCli(dir, [...args, "--ignore-path", ".prettierignore"], options);
|
|
|
|
|
|
|
2020-03-17 01:34:32 +02:00
|
|
|
|
// ESLint-like behavior
|
2023-09-25 14:45:01 +09:00
|
|
|
|
//
|
2020-03-17 01:34:32 +02:00
|
|
|
|
// https://github.com/prettier/prettier/pull/6639#issuecomment-548949954
|
|
|
|
|
|
//
|
2023-09-25 14:45:01 +09:00
|
|
|
|
// Since 3.0: https://github.com/prettier/prettier/pull/15155#issuecomment-1723654981
|
|
|
|
|
|
//
|
2020-03-17 01:34:32 +02:00
|
|
|
|
// 1. `prettier dir1 dir2` – prettify all files with supported extensions inside `dir1` and `dir2`.
|
|
|
|
|
|
//
|
|
|
|
|
|
// 2. `prettier dir1 "dir2/**/*"` – prettify all files with supported extensions inside `dir1`
|
|
|
|
|
|
// as well as all files matched by the `dir2/**/*` glob.
|
2023-09-25 14:45:01 +09:00
|
|
|
|
// Unsupported files are ignored as with `--ignore-unknown`.
|
2020-03-17 01:34:32 +02:00
|
|
|
|
//
|
|
|
|
|
|
// 3. `prettier non-exists-dir "dir2/**/*""` – log an error that `non-exists-dir` resulted in 0 files
|
|
|
|
|
|
// and prettify all files matched by the `dir2/**/*` glob.
|
2023-09-25 14:45:01 +09:00
|
|
|
|
// Unsupported files are ignored as with `--ignore-unknown`.
|
2020-03-17 01:34:32 +02:00
|
|
|
|
// (Note: ESLint just prints an error and doesn't process anything.)
|
|
|
|
|
|
//
|
|
|
|
|
|
// 4. `prettier . "dir2/**/*"` – prettify all files with supported extensions in `.`
|
|
|
|
|
|
// and all files matched by the `dir2/**/*` glob.
|
2023-09-25 14:45:01 +09:00
|
|
|
|
// Unsupported files are ignored as with `--ignore-unknown`.
|
2020-03-17 01:34:32 +02:00
|
|
|
|
//
|
|
|
|
|
|
// (*) That error ("No parser could be inferred for file") doesn't affect the error code.
|
|
|
|
|
|
|
|
|
|
|
|
testPatterns("1", ["dir1", "dir2"]);
|
|
|
|
|
|
testPatterns("1a - with *.foo plugin", [
|
|
|
|
|
|
"dir1",
|
|
|
|
|
|
"dir2",
|
2021-12-03 15:41:12 +08:00
|
|
|
|
"--plugin=../../plugins/extensions/plugin.cjs",
|
2020-03-17 01:34:32 +02:00
|
|
|
|
]);
|
|
|
|
|
|
testPatterns("1b - special characters in dir name", ["dir1", "!dir"], {
|
2025-12-21 23:44:08 +08:00
|
|
|
|
stdout: expect.stringMatching(/!dir[/\\]a\.js/),
|
2020-03-17 01:34:32 +02:00
|
|
|
|
});
|
2023-09-25 14:45:01 +09:00
|
|
|
|
testPatterns("1c", ["dir1", "empty"], { status: 1 });
|
2020-03-17 01:34:32 +02:00
|
|
|
|
|
2025-06-02 22:53:37 +08:00
|
|
|
|
testPatterns("2", ["dir1", "dir2/**/*"], { status: 2 });
|
2020-03-17 01:34:32 +02:00
|
|
|
|
|
|
|
|
|
|
testPatterns("3", ["nonexistent-dir", "dir2/**/*"], { status: 2 });
|
|
|
|
|
|
|
|
|
|
|
|
testPatterns("4", [".", "dir2/**/*"], { status: 1 });
|
|
|
|
|
|
|
2021-06-11 11:03:42 +08:00
|
|
|
|
describe("Trailing slash", () => {
|
|
|
|
|
|
testPatterns("1", ["./"], { status: 1, stderr: "" });
|
|
|
|
|
|
testPatterns("2", [".//"], { status: 1, stderr: "" });
|
|
|
|
|
|
testPatterns("3", ["dir1/"], { status: 1, stderr: "" });
|
|
|
|
|
|
testPatterns("4", ["dir1//"], { status: 1, stderr: "" });
|
|
|
|
|
|
testPatterns("5", [".//dir2/..//./dir1//"], { status: 1, stderr: "" });
|
|
|
|
|
|
testPatterns(
|
|
|
|
|
|
"run in sub dir 1",
|
|
|
|
|
|
[".."],
|
|
|
|
|
|
{ status: 1, stderr: "" },
|
|
|
|
|
|
"cli/patterns-dirs/dir2",
|
|
|
|
|
|
);
|
|
|
|
|
|
testPatterns(
|
|
|
|
|
|
"run in sub dir 2",
|
|
|
|
|
|
["../"],
|
|
|
|
|
|
{ status: 1, stderr: "" },
|
|
|
|
|
|
"cli/patterns-dirs/dir2",
|
|
|
|
|
|
);
|
|
|
|
|
|
testPatterns(
|
|
|
|
|
|
"run in sub dir 3",
|
|
|
|
|
|
["../dir1"],
|
|
|
|
|
|
{ status: 1, stderr: "" },
|
|
|
|
|
|
"cli/patterns-dirs/dir2",
|
|
|
|
|
|
);
|
|
|
|
|
|
testPatterns(
|
|
|
|
|
|
"run in sub dir 4",
|
|
|
|
|
|
["../dir1/"],
|
|
|
|
|
|
{ status: 1, stderr: "" },
|
|
|
|
|
|
"cli/patterns-dirs/dir2",
|
|
|
|
|
|
);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2020-03-17 01:34:32 +02:00
|
|
|
|
describe("Negative patterns", () => {
|
|
|
|
|
|
testPatterns("1", ["dir1", "!dir1/nested1"]);
|
|
|
|
|
|
testPatterns("1a", ["dir1", "!dir1/nested1/*"]);
|
|
|
|
|
|
testPatterns("2", [".", "!dir1/nested1"]);
|
|
|
|
|
|
testPatterns("3", [".", "!dir1/nested1/an1.js"]);
|
|
|
|
|
|
testPatterns("4", ["!nonexistent-dir1 !nonexistent-dir2"], { status: 2 });
|
|
|
|
|
|
testPatterns("with explicit files", ["dir1/a1.js", "dir2/a2.js", "!dir1/*"], {
|
|
|
|
|
|
status: 2,
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2020-03-22 22:57:12 +02:00
|
|
|
|
testPatterns("Exclude yarn.lock when expanding directories", ["."], {
|
|
|
|
|
|
stdout: expect.not.stringContaining("yarn.lock"),
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2020-08-06 23:15:19 +08:00
|
|
|
|
const uppercaseRocksPlugin = path.join(
|
|
|
|
|
|
projectRoot,
|
2022-08-06 10:42:27 +08:00
|
|
|
|
"tests/config/prettier-plugins/prettier-plugin-uppercase-rocks/index.js",
|
2020-08-06 23:15:19 +08:00
|
|
|
|
);
|
|
|
|
|
|
describe("plugins `.`", () => {
|
2023-05-04 17:20:05 +08:00
|
|
|
|
runCliWithoutGitignore("cli/dirs/plugins", [
|
2020-08-06 23:15:19 +08:00
|
|
|
|
".",
|
|
|
|
|
|
"-l",
|
|
|
|
|
|
"--plugin",
|
|
|
|
|
|
uppercaseRocksPlugin,
|
|
|
|
|
|
]).test({
|
|
|
|
|
|
write: [],
|
|
|
|
|
|
stderr: "",
|
|
|
|
|
|
status: 1,
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
describe("plugins `*`", () => {
|
2023-05-04 17:20:05 +08:00
|
|
|
|
runCliWithoutGitignore("cli/dirs/plugins", [
|
2020-08-06 23:15:19 +08:00
|
|
|
|
"*",
|
|
|
|
|
|
"-l",
|
|
|
|
|
|
"--plugin",
|
|
|
|
|
|
uppercaseRocksPlugin,
|
|
|
|
|
|
]).test({
|
|
|
|
|
|
write: [],
|
2025-06-02 22:53:37 +08:00
|
|
|
|
status: 2,
|
2020-08-06 23:15:19 +08:00
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2020-03-17 01:34:32 +02:00
|
|
|
|
if (path.sep === "/") {
|
|
|
|
|
|
// Don't use snapshots in these tests as they're conditionally executed on non-Windows only.
|
|
|
|
|
|
|
2025-04-21 18:58:44 +08:00
|
|
|
|
const base = path.resolve(__dirname, "../cli/patterns-backslashes");
|
|
|
|
|
|
const directoryA = path.join(base, "test-a\\");
|
|
|
|
|
|
const directoryB = path.join(base, String.raw`test-b\?`);
|
|
|
|
|
|
|
|
|
|
|
|
fs.rmSync(directoryA, { force: true, recursive: true });
|
|
|
|
|
|
fs.rmSync(directoryB, { force: true, recursive: true });
|
|
|
|
|
|
for (const directory of [directoryA, directoryB]) {
|
|
|
|
|
|
fs.mkdirSync(directory);
|
|
|
|
|
|
fs.writeFileSync(path.join(directory, "test.js"), "x");
|
|
|
|
|
|
}
|
2020-03-17 01:34:32 +02:00
|
|
|
|
|
|
|
|
|
|
describe("Backslashes in names", () => {
|
2025-04-21 18:58:44 +08:00
|
|
|
|
testPatterns(
|
|
|
|
|
|
"",
|
|
|
|
|
|
[String.raw`test-a\/test.js`],
|
|
|
|
|
|
{
|
|
|
|
|
|
stdout: String.raw`test-a\/test.js`,
|
|
|
|
|
|
},
|
|
|
|
|
|
base,
|
|
|
|
|
|
);
|
|
|
|
|
|
testPatterns(
|
|
|
|
|
|
"",
|
|
|
|
|
|
["test-a\\"],
|
|
|
|
|
|
{ stdout: String.raw`test-a\/test.js` },
|
|
|
|
|
|
base,
|
|
|
|
|
|
);
|
|
|
|
|
|
testPatterns(
|
|
|
|
|
|
"",
|
|
|
|
|
|
["test-a*/*"],
|
|
|
|
|
|
{ stdout: String.raw`test-a\/test.js` },
|
|
|
|
|
|
base,
|
|
|
|
|
|
);
|
2021-05-09 20:43:10 +08:00
|
|
|
|
|
2025-04-21 18:58:44 +08:00
|
|
|
|
testPatterns(
|
|
|
|
|
|
"",
|
|
|
|
|
|
[String.raw`test-b\?/test.js`],
|
|
|
|
|
|
{
|
|
|
|
|
|
stdout: String.raw`test-b\?/test.js`,
|
|
|
|
|
|
},
|
|
|
|
|
|
base,
|
|
|
|
|
|
);
|
|
|
|
|
|
testPatterns(
|
|
|
|
|
|
"",
|
|
|
|
|
|
[String.raw`test-b\?`],
|
|
|
|
|
|
{
|
|
|
|
|
|
stdout: String.raw`test-b\?/test.js`,
|
|
|
|
|
|
},
|
|
|
|
|
|
base,
|
|
|
|
|
|
);
|
|
|
|
|
|
testPatterns(
|
|
|
|
|
|
"",
|
|
|
|
|
|
["test-b*/*"],
|
|
|
|
|
|
{ stdout: String.raw`test-b\?/test.js` },
|
|
|
|
|
|
base,
|
|
|
|
|
|
);
|
2020-03-17 01:34:32 +02:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-05-04 02:01:20 -07:00
|
|
|
|
function isSymlinkSupported() {
|
|
|
|
|
|
if (process.platform !== "win32") {
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const target = path.join(
|
|
|
|
|
|
__dirname,
|
|
|
|
|
|
"../cli/patterns-symlinks/test-symlink-feature-detect",
|
|
|
|
|
|
);
|
|
|
|
|
|
fs.rmSync(target, { force: true, recursive: true });
|
|
|
|
|
|
fs.mkdirSync(target);
|
|
|
|
|
|
const symlink = path.join(target, "symlink");
|
|
|
|
|
|
try {
|
|
|
|
|
|
fs.symlinkSync(target, symlink);
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
return fs.lstatSync(symlink).isSymbolicLink();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
(isSymlinkSupported() ? describe : describe.skip)("Ignore symlinks", () => {
|
|
|
|
|
|
const base = path.join(__dirname, "../cli/patterns-symlinks");
|
|
|
|
|
|
const directoryA = path.join(base, "test-a");
|
|
|
|
|
|
const directoryB = path.join(base, "test-b");
|
2025-04-21 18:58:44 +08:00
|
|
|
|
|
|
|
|
|
|
fs.rmSync(directoryA, { force: true, recursive: true });
|
|
|
|
|
|
fs.rmSync(directoryB, { force: true, recursive: true });
|
|
|
|
|
|
fs.mkdirSync(directoryA);
|
|
|
|
|
|
fs.mkdirSync(directoryB);
|
|
|
|
|
|
fs.writeFileSync(path.join(directoryA, "a.js"), "x");
|
|
|
|
|
|
fs.writeFileSync(path.join(directoryB, "b.js"), "x");
|
|
|
|
|
|
fs.symlinkSync(directoryA, path.join(directoryA, "symlink-to-directory-a"));
|
|
|
|
|
|
fs.symlinkSync(directoryB, path.join(directoryA, "symlink-to-directory-b"));
|
|
|
|
|
|
fs.symlinkSync(
|
|
|
|
|
|
path.join(directoryA, "a.js"),
|
|
|
|
|
|
path.join(directoryA, "symlink-to-file-a"),
|
|
|
|
|
|
);
|
|
|
|
|
|
fs.symlinkSync(
|
|
|
|
|
|
path.join(directoryB, "b.js"),
|
|
|
|
|
|
path.join(directoryA, "symlink-to-file-b"),
|
|
|
|
|
|
);
|
2023-05-04 02:01:20 -07:00
|
|
|
|
|
|
|
|
|
|
test("file struct", async () => {
|
|
|
|
|
|
const getFileStruct = async (directory) =>
|
|
|
|
|
|
(await fs.promises.readdir(directory, { withFileTypes: true }))
|
|
|
|
|
|
.map((dirent) => ({
|
|
|
|
|
|
name: dirent.name,
|
|
|
|
|
|
isSymbolicLink: dirent.isSymbolicLink(),
|
|
|
|
|
|
}))
|
|
|
|
|
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
|
|
|
|
|
|
|
|
|
|
expect(await getFileStruct(directoryA)).toMatchInlineSnapshot(`
|
|
|
|
|
|
[
|
|
|
|
|
|
{
|
|
|
|
|
|
"isSymbolicLink": false,
|
|
|
|
|
|
"name": "a.js",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"isSymbolicLink": true,
|
|
|
|
|
|
"name": "symlink-to-directory-a",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"isSymbolicLink": true,
|
|
|
|
|
|
"name": "symlink-to-directory-b",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"isSymbolicLink": true,
|
|
|
|
|
|
"name": "symlink-to-file-a",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"isSymbolicLink": true,
|
|
|
|
|
|
"name": "symlink-to-file-b",
|
|
|
|
|
|
},
|
|
|
|
|
|
]
|
|
|
|
|
|
`);
|
|
|
|
|
|
expect(await getFileStruct(directoryB)).toMatchInlineSnapshot(`
|
|
|
|
|
|
[
|
|
|
|
|
|
{
|
|
|
|
|
|
"isSymbolicLink": false,
|
|
|
|
|
|
"name": "b.js",
|
|
|
|
|
|
},
|
|
|
|
|
|
]
|
|
|
|
|
|
`);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
testPatterns("", ["test-a/*"], { stdout: "test-a/a.js" }, base);
|
|
|
|
|
|
testPatterns(
|
|
|
|
|
|
"",
|
|
|
|
|
|
["test-a/symlink-to-directory-a"],
|
|
|
|
|
|
{
|
|
|
|
|
|
status: 2,
|
|
|
|
|
|
stdout: "",
|
|
|
|
|
|
stderr:
|
|
|
|
|
|
'[error] Explicitly specified pattern "test-a/symlink-to-directory-a" is a symbolic link.',
|
|
|
|
|
|
},
|
|
|
|
|
|
base,
|
|
|
|
|
|
);
|
|
|
|
|
|
testPatterns(
|
|
|
|
|
|
"",
|
|
|
|
|
|
["test-a/symlink-to-directory-b"],
|
|
|
|
|
|
{
|
|
|
|
|
|
status: 2,
|
|
|
|
|
|
stdout: "",
|
|
|
|
|
|
stderr:
|
|
|
|
|
|
'[error] Explicitly specified pattern "test-a/symlink-to-directory-b" is a symbolic link.',
|
|
|
|
|
|
},
|
|
|
|
|
|
base,
|
|
|
|
|
|
);
|
|
|
|
|
|
testPatterns(
|
|
|
|
|
|
"",
|
|
|
|
|
|
["test-a/symlink-to-file-a"],
|
|
|
|
|
|
{
|
|
|
|
|
|
status: 2,
|
|
|
|
|
|
stdout: "",
|
|
|
|
|
|
stderr:
|
|
|
|
|
|
'[error] Explicitly specified pattern "test-a/symlink-to-file-a" is a symbolic link.',
|
|
|
|
|
|
},
|
|
|
|
|
|
base,
|
|
|
|
|
|
);
|
|
|
|
|
|
testPatterns(
|
|
|
|
|
|
"",
|
|
|
|
|
|
["test-a/symlink-to-file-b"],
|
|
|
|
|
|
{
|
|
|
|
|
|
status: 2,
|
|
|
|
|
|
stdout: "",
|
|
|
|
|
|
stderr:
|
|
|
|
|
|
'[error] Explicitly specified pattern "test-a/symlink-to-file-b" is a symbolic link.',
|
|
|
|
|
|
},
|
|
|
|
|
|
base,
|
|
|
|
|
|
);
|
|
|
|
|
|
testPatterns(
|
|
|
|
|
|
"",
|
|
|
|
|
|
["test-a/symlink-*"],
|
|
|
|
|
|
{
|
|
|
|
|
|
status: 2,
|
|
|
|
|
|
stdout: "",
|
|
|
|
|
|
stderr:
|
|
|
|
|
|
'[error] No files matching the pattern were found: "test-a/symlink-*".',
|
|
|
|
|
|
},
|
|
|
|
|
|
base,
|
|
|
|
|
|
);
|
|
|
|
|
|
testPatterns(
|
|
|
|
|
|
"",
|
|
|
|
|
|
["test-a/*", "test-a/symlink-to-file-b"],
|
|
|
|
|
|
{
|
|
|
|
|
|
status: 2,
|
|
|
|
|
|
stdout: "test-a/a.js",
|
|
|
|
|
|
stderr:
|
|
|
|
|
|
'[error] Explicitly specified pattern "test-a/symlink-to-file-b" is a symbolic link.',
|
|
|
|
|
|
},
|
|
|
|
|
|
base,
|
|
|
|
|
|
);
|
|
|
|
|
|
testPatterns(
|
|
|
|
|
|
"",
|
|
|
|
|
|
["test-a/symlink-to-directory-b/*"],
|
|
|
|
|
|
{ stdout: "test-a/symlink-to-directory-b/b.js" },
|
|
|
|
|
|
base,
|
|
|
|
|
|
);
|
2023-12-07 17:54:18 +01:00
|
|
|
|
|
|
|
|
|
|
testPatterns(
|
|
|
|
|
|
"",
|
|
|
|
|
|
[
|
|
|
|
|
|
"test-a/symlink-to-file-b",
|
|
|
|
|
|
"--no-error-on-unmatched-pattern",
|
|
|
|
|
|
"--log-level",
|
|
|
|
|
|
"debug",
|
|
|
|
|
|
],
|
|
|
|
|
|
{
|
|
|
|
|
|
status: 0,
|
|
|
|
|
|
stdout: "",
|
|
|
|
|
|
stderr:
|
2025-11-16 20:10:48 +08:00
|
|
|
|
'[debug] normalized argv: {"_":["test-a/symlink-to-file-b"],"cache":false,"color":true,"editorconfig":true,"errorOnUnmatchedPattern":false,"logLevel":"debug","ignorePath":[".prettierignore"],"configPrecedence":"cli-override","debugRepeat":0,"plugins":[],"listDifferent":true,"__raw":{"_":["test-a/symlink-to-file-b"],"cache":false,"color":true,"editorconfig":true,"error-on-unmatched-pattern":false,"l":true,"log-level":"debug","ignore-path":".prettierignore","config-precedence":"cli-override","debug-repeat":0,"plugin":[]}}' +
|
2023-12-07 17:54:18 +01:00
|
|
|
|
"\n" +
|
|
|
|
|
|
'[debug] Skipping pattern "test-a/symlink-to-file-b", as it is a symbolic link.',
|
|
|
|
|
|
},
|
|
|
|
|
|
base,
|
|
|
|
|
|
);
|
2023-05-04 02:01:20 -07:00
|
|
|
|
});
|
|
|
|
|
|
|
2021-06-11 11:03:42 +08:00
|
|
|
|
function testPatterns(
|
|
|
|
|
|
namePrefix,
|
|
|
|
|
|
cliArgs,
|
|
|
|
|
|
expected = {},
|
|
|
|
|
|
cwd = "cli/patterns-dirs",
|
|
|
|
|
|
) {
|
2020-03-17 01:34:32 +02:00
|
|
|
|
const testName =
|
|
|
|
|
|
(namePrefix ? namePrefix + ": " : "") +
|
|
|
|
|
|
"prettier " +
|
|
|
|
|
|
cliArgs
|
2025-12-21 23:44:08 +08:00
|
|
|
|
.map((arg) => (/^[\w./=-]+$/.test(arg) ? arg : `'${arg}'`))
|
2020-03-17 01:34:32 +02:00
|
|
|
|
.join(" ");
|
|
|
|
|
|
|
|
|
|
|
|
describe(testName, () => {
|
2023-05-04 17:20:05 +08:00
|
|
|
|
runCliWithoutGitignore(cwd, [...cliArgs, "-l"]).test({
|
2020-03-17 01:34:32 +02:00
|
|
|
|
write: [],
|
2026-06-22 13:43:03 +08:00
|
|
|
|
...("status" in expected ? {} : { stderr: "", status: 1 }),
|
2020-03-17 01:34:32 +02:00
|
|
|
|
...expected,
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|