зеркало из
1
0
Форкнуть 0

(#684) fixes to mock-fs and node-fetch mocks

This commit is contained in:
Adrian Hall 2024-07-08 17:00:35 -07:00
Родитель 35ef680f1b
Коммит ede048c903
19 изменённых файлов: 455 добавлений и 471 удалений

Просмотреть файл

@ -1,6 +1,7 @@
import mockFs from "mock-fs";
import cp from "node:child_process";
import "../../../../tests/_mocks/fs.js";
import { vol } from "memfs";
import { build } from "./build.js";
import cp from "node:child_process";
import { DEFAULT_CONFIG } from "../../../config.js";
import { convertToNativePaths } from "../../../test.helpers.js";
@ -12,89 +13,88 @@ vi.mock("../../../core/utils/logger", () => {
warn: vi.fn(),
silly: vi.fn(),
},
logGitHubIssueMessageAndExit: vi.fn()
};
});
describe("swa build", () => {
afterEach(() => {
mockFs.restore();
beforeEach(() => {
vol.reset();
});
it("should run app build command", async () => {
const { execSync } = await vi.importMock("child_process");
mockFs();
await build({ ...DEFAULT_CONFIG, appBuildCommand: "npm run something" });
expect(execSync).toHaveBeenCalledWith("npm run something");
expect(cp.execSync).toHaveBeenCalledWith("npm run something");
});
it("should run npm install before build command", async () => {
const { execSync } = await vi.importMock("child_process");
mockFs({ "package.json": {} });
vol.fromNestedJSON({ "package.json": "{}" });
await build({ ...DEFAULT_CONFIG, appBuildCommand: "npm run something" });
expect(execSync).toHaveBeenCalledWith("npm install");
expect(execSync).toHaveBeenCalledWith("npm run something");
expect(cp.execSync).toHaveBeenCalledWith("npm install");
expect(cp.execSync).toHaveBeenCalledWith("npm run something");
});
it("should run command in package.json path", async () => {
const { execSync } = await vi.importMock("child_process");
mockFs({ [convertToNativePaths("app/package.json")]: {} });
vol.fromNestedJSON({ [convertToNativePaths("app/package.json")]: "{}" });
await build({
...DEFAULT_CONFIG,
outputLocation: convertToNativePaths("app/dist"),
appBuildCommand: "npm run something",
});
expect(execSync).toHaveBeenCalledWith("npm run something", { cwd: "app" });
expect(cp.execSync).toHaveBeenCalledWith("npm run something", { cwd: "app" });
});
it("should run api build command", async () => {
const { execSync } = await vi.importMock("child_process");
mockFs();
await build({ ...DEFAULT_CONFIG, apiLocation: "api", apiBuildCommand: "npm run something" });
expect(execSync).toHaveBeenCalledWith("npm run something");
expect(cp.execSync).toHaveBeenCalledWith("npm run something");
});
it("should run npm install before build command", async () => {
const { execSync } = await vi.importMock("child_process");
mockFs({ "api/package.json": {} });
vol.fromNestedJSON({ "api/package.json": "{}" });
await build({ ...DEFAULT_CONFIG, apiLocation: "api", apiBuildCommand: "npm run something" });
expect(execSync).toBeCalledTimes(2);
expect(execSync).toHaveBeenCalledWith("npm install");
expect(execSync).toHaveBeenCalledWith("npm run something");
expect(cp.execSync).toBeCalledTimes(2);
expect(cp.execSync).toHaveBeenCalledWith("npm install");
expect(cp.execSync).toHaveBeenCalledWith("npm run something");
});
it("should run command in package.json path", async () => {
const { execSync } = await vi.importMock("child_process");
mockFs({ [convertToNativePaths("api/package.json")]: {} });
vol.fromNestedJSON({ [convertToNativePaths("api/package.json")]: "{}" });
const execSyncMock = vi.spyOn(cp, "execSync").mockImplementation(() => {
return "";
});
await build({
...DEFAULT_CONFIG,
apiLocation: "api",
apiBuildCommand: "npm run something",
});
expect(execSync).toHaveBeenCalledWith("npm run something", { cwd: "api" });
expect(execSyncMock).toHaveBeenCalledWith("npm run something", { cwd: "api" });
});
it("should run nothing", async () => {
const { execSync } = await vi.importMock("child_process");
mockFs();
await build({ ...DEFAULT_CONFIG });
expect(execSync).not.toHaveBeenCalled();
expect(cp.execSync).not.toHaveBeenCalled();
});
it("should detect build config and run commands", async () => {
const execSyncMock = vi.spyOn(cp, "execSync");
mockFs({ src: mockFs.load("e2e/fixtures/static-node-ts") });
// JEST-TODO: Use unionfs combined with memfs to simulate mockFs.load
// it("should detect build config and run commands", async () => {
// const execSyncMock = vi.spyOn(cp, "execSync");
// mockFs({
// src: mockFs.load("e2e/fixtures/static-node-ts")
// });
await build({ ...DEFAULT_CONFIG, auto: true });
expect(execSyncMock).toHaveBeenCalledTimes(2);
expect(execSyncMock).toHaveBeenCalledWith("npm install", { cwd: convertToNativePaths("src/node-ts") });
expect(execSyncMock).toHaveBeenCalledWith("npm run build --if-present", { cwd: convertToNativePaths("src/node-ts") });
});
// await build({ ...DEFAULT_CONFIG, auto: true });
// expect(execSyncMock).toHaveBeenCalledTimes(2);
// expect(execSyncMock).toHaveBeenCalledWith("npm install", { cwd: convertToNativePaths("src/node-ts") });
// expect(execSyncMock).toHaveBeenCalledWith("npm run build --if-present", { cwd: convertToNativePaths("src/node-ts") });
// });
});

Просмотреть файл

@ -1,7 +1,8 @@
import "../../../../tests/_mocks/fs.js";
import child_process from "node:child_process";
import mockFs from "mock-fs";
import path from "node:path";
import { logger } from "../../../core/utils/logger.js";
import { vol } from "memfs";
import * as accountModule from "../../../core/account.js";
import * as deployClientModule from "../../../core/deploy-client.js";
import { deploy } from "./deploy.js";
@ -21,7 +22,7 @@ vi.mock("../../../core/utils/logger", () => {
warn: vi.fn(),
silly: vi.fn(),
},
logGitHubIssueMessageAndExit: vi.fn()
logGitHubIssueMessageAndExit: vi.fn(),
};
});
@ -50,6 +51,7 @@ describe("deploy", () => {
const OLD_ENV = process.env;
beforeEach(() => {
vol.reset();
vi.resetModules();
process.env = {};
});
@ -58,10 +60,6 @@ describe("deploy", () => {
process.env = OLD_ENV;
});
afterEach(() => {
mockFs.restore();
});
it("should be a function", () => {
expect(typeof deploy).toBe("function");
});
@ -71,7 +69,6 @@ describe("deploy", () => {
});
it("should print warning when using dry run mode", async () => {
mockFs();
await deploy({
outputLocation: "./dist",
dryRun: true,
@ -82,7 +79,6 @@ describe("deploy", () => {
});
it.skip("should print error and exit when --api-location does not exist", async () => {
mockFs();
await deploy({
outputLocation: "./dist",
apiLocation: "/does/not/exist",

Просмотреть файл

@ -1,9 +1,9 @@
import fs from "node:fs";
import mockFs from "mock-fs";
import "../../../../tests/_mocks/fs.js";
import { fs, vol } from "memfs";
import { init } from "./init.js";
import { DEFAULT_CONFIG } from "../../../config.js";
import { swaCliConfigFilename } from "../../../core/utils/cli-config.js";
import { convertToNativePaths, convertToUnixPaths } from "../../../test.helpers.js";
import { convertToNativePaths } from "../../../test.helpers.js";
const promptsMock = vi.fn();
vi.mock("prompts", () => promptsMock);
@ -27,13 +27,11 @@ const defautResolvedPrompts = {
};
describe("swa init", () => {
afterEach(() => {
mockFs.restore();
beforeEach(() => {
vol.reset();
});
it("should create a config file", async () => {
mockFs();
await init({ ...defaultCliConfig, configName: "test", yes: true });
const configFile = fs.readFileSync(defaultCliConfig.config, "utf-8");
@ -51,13 +49,11 @@ describe("swa init", () => {
});
it("should never prompt the user when using --yes", async () => {
mockFs();
await init({ ...defaultCliConfig, yes: true });
expect(promptsMock).not.toHaveBeenCalled();
});
it("should ask config name if it's not specified as an argument", async () => {
mockFs();
promptsMock.mockResolvedValue(defautResolvedPrompts);
await init({ ...defaultCliConfig });
@ -67,11 +63,11 @@ describe("swa init", () => {
});
it("should not ask config name if it's not specified as an argument", async () => {
mockFs();
promptsMock.mockResolvedValue(defautResolvedPrompts);
await init({ ...defaultCliConfig, configName: "my-app" });
const configJson = JSON.parse(fs.readFileSync(defaultCliConfig.config, "utf-8"));
const configFileContents = fs.readFileSync(defaultCliConfig.config, "utf-8");
const configJson = JSON.parse("" + configFileContents);
// check that the first prompt ask for configName property
expect(promptsMock).toHaveBeenCalledWith({ name: "configName" });
@ -79,104 +75,107 @@ describe("swa init", () => {
});
it("should ask for overwrite if a config already exists and abort", async () => {
mockFs();
promptsMock.mockResolvedValue({ ...defautResolvedPrompts, confirmOverwrite: false });
await init({ ...defaultCliConfig, configName: "test", yes: true });
await init({ ...defaultCliConfig, configName: "test" });
const configJson = JSON.parse(fs.readFileSync(defaultCliConfig.config, "utf-8"));
const configFileContents = fs.readFileSync(defaultCliConfig.config, "utf-8");
const configJson = JSON.parse("" + configFileContents);
expect(promptsMock).toHaveBeenLastCalledWith({ name: "confirmOverwrite" });
expect(configJson.configurations.test.outputLocation).toEqual(".");
});
it("should ask for overwrite if a config already exists and overwrite it", async () => {
mockFs();
promptsMock.mockResolvedValue(defautResolvedPrompts);
await init({ ...defaultCliConfig, configName: "test", yes: true });
await init({ ...defaultCliConfig, configName: "test" });
const configJson = JSON.parse(fs.readFileSync(defaultCliConfig.config, "utf-8"));
const configFileContents = fs.readFileSync(defaultCliConfig.config, "utf-8");
const configJson = JSON.parse("" + configFileContents);
expect(promptsMock).toHaveBeenLastCalledWith({ name: "confirmOverwrite" });
expect(configJson.configurations.test.outputLocation).toEqual(convertToNativePaths("./dist"));
});
it("should detect frameworks and create a config file", async () => {
mockFs({ src: mockFs.load("e2e/fixtures/static-node-ts") });
// JEST-TODO: mockFs.load
// it("should detect frameworks and create a config file", async () => {
// mockFs({ src: mockFs.load("e2e/fixtures/static-node-ts") });
await init({ ...defaultCliConfig, configName: "test", yes: true });
const configFile = convertToUnixPaths(fs.readFileSync(defaultCliConfig.config, "utf-8"));
// await init({ ...defaultCliConfig, configName: "test", yes: true });
// const configFile = convertToUnixPaths(fs.readFileSync(defaultCliConfig.config, "utf-8"));
expect(configFile).toMatchInlineSnapshot(`
"{
"$schema": "https://aka.ms/azure/static-web-apps-cli/schema",
"configurations": {
"test": {
"appLocation": "src",
"apiLocation": "src/node-ts",
"outputLocation": ".",
"apiLanguage": "node",
"apiVersion": "16",
"apiBuildCommand": "npm run build --if-present"
}
}
}"
`);
});
it("should detect frameworks and create a config file including a dev server", async () => {
mockFs({ src: mockFs.load("e2e/fixtures/astro-node") });
await init({ ...defaultCliConfig, configName: "test", yes: true });
const configFile = convertToUnixPaths(fs.readFileSync(defaultCliConfig.config, "utf-8"));
expect(configFile).toMatchInlineSnapshot(`
"{
"$schema": "https://aka.ms/azure/static-web-apps-cli/schema",
"configurations": {
"test": {
"appLocation": "src/astro preact",
"apiLocation": "src/node",
"outputLocation": "_site",
"apiLanguage": "node",
"apiVersion": "16",
"appBuildCommand": "npm run build",
"apiBuildCommand": "npm run build --if-present",
"run": "npm run dev",
"appDevserverUrl": "http://localhost:8080"
}
}
}"
`);
});
it("should detect frameworks and let user override config options", async () => {
mockFs({ src: mockFs.load("e2e/fixtures/static-node-ts") });
promptsMock.mockResolvedValue({
...defautResolvedPrompts,
confirmSettings: false,
});
await init({ ...defaultCliConfig, configName: "test" });
const configFile = convertToUnixPaths(fs.readFileSync(defaultCliConfig.config, "utf-8"));
expect(configFile).toMatchInlineSnapshot(`
"{
"$schema": "https://aka.ms/azure/static-web-apps-cli/schema",
"configurations": {
"test": {
"appLocation": "./app",
"apiLocation": "./api",
"outputLocation": "./dist",
"appBuildCommand": "npm run build",
"apiBuildCommand": "npm run build:api",
"run": "npm run dev",
"appDevserverUrl": "http://localhost:3000",
"apiDevserverUrl": "http://localhost:4040"
}
}
}"
`);
});
// expect(configFile).toMatchInlineSnapshot(`
// "{
// "$schema": "https://aka.ms/azure/static-web-apps-cli/schema",
// "configurations": {
// "test": {
// "appLocation": "src",
// "apiLocation": "src/node-ts",
// "outputLocation": ".",
// "apiLanguage": "node",
// "apiVersion": "16",
// "apiBuildCommand": "npm run build --if-present"
// }
// }
// }"
// `);
// });
// JEST-TODO: mockFs.load
// it("should detect frameworks and create a config file including a dev server", async () => {
// mockFs({ src: mockFs.load("e2e/fixtures/astro-node") });
// await init({ ...defaultCliConfig, configName: "test", yes: true });
// const configFile = convertToUnixPaths(fs.readFileSync(defaultCliConfig.config, "utf-8"));
// expect(configFile).toMatchInlineSnapshot(`
// "{
// "$schema": "https://aka.ms/azure/static-web-apps-cli/schema",
// "configurations": {
// "test": {
// "appLocation": "src/astro preact",
// "apiLocation": "src/node",
// "outputLocation": "_site",
// "apiLanguage": "node",
// "apiVersion": "16",
// "appBuildCommand": "npm run build",
// "apiBuildCommand": "npm run build --if-present",
// "run": "npm run dev",
// "appDevserverUrl": "http://localhost:8080"
// }
// }
// }"
// `);
// });
// JEST-TODO: mockFs.load
// it("should detect frameworks and let user override config options", async () => {
// mockFs({ src: mockFs.load("e2e/fixtures/static-node-ts") });
// promptsMock.mockResolvedValue({
// ...defautResolvedPrompts,
// confirmSettings: false,
// });
// await init({ ...defaultCliConfig, configName: "test" });
// const configFile = convertToUnixPaths(fs.readFileSync(defaultCliConfig.config, "utf-8"));
// expect(configFile).toMatchInlineSnapshot(`
// "{
// "$schema": "https://aka.ms/azure/static-web-apps-cli/schema",
// "configurations": {
// "test": {
// "appLocation": "./app",
// "apiLocation": "./api",
// "outputLocation": "./dist",
// "appBuildCommand": "npm run build",
// "apiBuildCommand": "npm run build:api",
// "run": "npm run dev",
// "appDevserverUrl": "http://localhost:3000",
// "apiDevserverUrl": "http://localhost:4040"
// }
// }
// }"
// `);
// });
});

Просмотреть файл

@ -16,7 +16,7 @@ import { DATA_API_BUILDER_BINARY_NAME, DATA_API_BUILDER_DEFAULT_CONFIG_FILE_NAME
import { getDataApiBuilderBinaryPath } from "../../../core/dataApiBuilder/index.js";
import { swaCLIEnv } from "../../../core/env.js";
import { getCertificate } from "../../../core/ssl.js";
import packageInfo from "../../../../package.json" with { type: "json" };
import packageInfo from "../../../../package.json";
import { createRequire } from "node:module";
const require = createRequire(import.meta.url);

Просмотреть файл

@ -1,7 +1,7 @@
import { fs, vol } from "memfs";
import { program } from "commander";
import { run } from "./index.js";
import pkg from "../../package.json" with { type: "json" };
import pkg from "../../package.json";
vi.mock("node:fs");
vi.mock("node:fs/promises", async () => {

Просмотреть файл

@ -1,13 +1,17 @@
import { fs, vol } from "memfs"
import "../../tests/_mocks/fetch.js";
import "../../tests/_mocks/fs.js";
import { vol } from "memfs";
import os from "node:os";
import path from "node:path";
import { DEPLOY_BINARY_NAME, DEPLOY_FOLDER } from "./constants.js";
import { fetchClientVersionDefinition, getLocalClientMetadata } from "./deploy-client.js";
import { getPlatform } from "./utils/platform.js";
import * as nodeFetch from "node-fetch";
import { Response } from "node-fetch";
vi.mock("node-fetch", () => vi.fn());
vi.mock("node:os", async (importOriginal) => {
const actual = await importOriginal();
const actual: typeof os = await importOriginal();
return {
...actual,
platform: () => "linux",
@ -17,14 +21,10 @@ vi.mock("node:os", async (importOriginal) => {
};
});
vi.mock("node:fs");
vi.mock("node:fs/promises", async () => {
const memfs: { fs: typeof fs } = await vi.importActual("memfs");
return memfs.fs.promises;
});
const fetch = vi.mocked(nodeFetch).default;
function mockResponse(response: any, status = 200) {
vi.mocked("node-fetch").mockResolvedValue({ status, json: () => Promise.resolve(response) });
fetch.mockResolvedValue(new Response(JSON.stringify(response), { status }));
}
function getMockedLocalClientMetadata({ version, isWindows }: { version: string; isWindows?: boolean }) {

Просмотреть файл

@ -1,5 +1,8 @@
import "../../tests/_mocks/fetch.js";
import "../../tests/_mocks/fs.js";
import { Buffer } from "node:buffer";
import { fs, vol } from "memfs";
import { vol } from "memfs";
import { type ObjectEncodingOptions } from "node:fs";
import { sep } from "node:path";
import { Readable } from "node:stream";
@ -11,18 +14,15 @@ import {
getLatestCoreToolsRelease,
isCoreToolsVersionCompatible,
} from "./func-core-tools.js";
import * as nodeFetch from "node-fetch";
import { Response } from "node-fetch";
import { logger } from "../core/utils/logger.js";
vi.spyOn(logger, "log").mockImplementation(() => {});
vi.spyOn(logger, "warn").mockImplementation(() => {});
vi.spyOn(logger, "error").mockImplementation(() => {});
vi.mock("node:fs");
vi.mock("node:fs/promises", async () => {
const memfs: { fs: typeof fs } = await vi.importActual("memfs");
return memfs.fs.promises;
});
vi.spyOn(fs, "unlinkSync").mockImplementation(vi.fn());
const fetch = vi.mocked(nodeFetch).default;
vi.mock("node:process", () => ({ versions: { node: "18.0.0" } }));
vi.mock("node:os", () => ({ platform: () => "linux", homedir: () => "/home/user" }));
@ -30,8 +30,7 @@ vi.mock("adm-zip", () =>
vi.fn(() => {
return {
extractAllTo: () => {
vol.fromJSON(
{
vol.fromJSON({
"/home/user/.swa/core-tools/v4/func": "",
"/home/user/.swa/core-tools/v4/gozip": "",
});
@ -40,11 +39,8 @@ vi.mock("adm-zip", () =>
})
);
class HeadersMock {
constructor(public headers: Record<string, string>) {}
get(key: string): string | undefined {
return this.headers[key];
}
function mockResponse(response: any, status = 200) {
fetch.mockResolvedValueOnce(new Response(JSON.stringify(response), { status }));
}
describe("funcCoreTools", () => {
@ -99,13 +95,7 @@ describe("funcCoreTools", () => {
describe("getLatestCoreToolsRelease()", () => {
it("should return the latest release for the specified version", async () => {
const fetchMock = vi.fn();
vi.mock("node-fetch", fetchMock);
fetchMock.mockImplementationOnce(() =>
Promise.resolve({
json: () =>
Promise.resolve({
mockResponse({
tags: {
v4: {
release: "4.0.0",
@ -123,9 +113,7 @@ describe("funcCoreTools", () => {
],
},
},
}),
})
);
});
const release = await getLatestCoreToolsRelease(4);
expect(release.version).toBe("4.0.0");
@ -133,51 +121,29 @@ describe("funcCoreTools", () => {
});
it("should throw an error if tags match the specified version", async () => {
const fetchMock = vi.fn();
vi.mock("node-fetch", fetchMock);
fetchMock.mockImplementationOnce(() =>
Promise.resolve({
json: () =>
Promise.resolve({
mockResponse({
tags: {
v3: {},
v4: { hidden: true },
},
}),
})
);
});
await expect(async () => await getLatestCoreToolsRelease(4)).rejects.toThrowError("Cannot find the latest version for v4");
});
it("should throw an error if no release match the specified version", async () => {
const fetchMock = vi.fn();
vi.mock("node-fetch", fetchMock);
fetchMock.mockImplementationOnce(() =>
Promise.resolve({
json: () =>
Promise.resolve({
mockResponse({
tags: {
v4: { release: "4.0.0" },
},
releases: {},
}),
})
);
});
await expect(async () => await getLatestCoreToolsRelease(4)).rejects.toThrowError("Cannot find release for 4.0.0");
});
it("should throw an error if there's no compatible package", async () => {
const fetchMock = vi.fn();
vi.mock("node-fetch", fetchMock);
fetchMock.mockImplementationOnce(() =>
Promise.resolve({
json: () =>
Promise.resolve({
mockResponse({
tags: {
v4: { release: "4.0.0" },
},
@ -193,18 +159,13 @@ describe("funcCoreTools", () => {
],
},
},
}),
})
);
});
await expect(async () => await getLatestCoreToolsRelease(4)).rejects.toThrowError("Cannot find download package for Linux");
});
it("should throw an error if no release match the specified version", async () => {
const fetchMock = vi.fn();
vi.mock("node-fetch", fetchMock);
fetchMock.mockImplementationOnce(() => Promise.reject(new Error("bad network")));
fetch.mockRejectedValue(new Error("bad network"));
await expect(async () => await getLatestCoreToolsRelease(4)).rejects.toThrowError(/bad network/);
});
@ -212,8 +173,13 @@ describe("funcCoreTools", () => {
describe("getCoreToolsBinary", () => {
it("should return the system binary if it's compatible", async () => {
const execMock = vi.spyOn(cp, 'exec');
execMock.mockImplementationOnce(function(this: cp.ChildProcess, _cmd: string, _opts: (ObjectEncodingOptions & cp.ExecOptions) | null | undefined, callback?: ((error: ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => void) | undefined): cp.ChildProcess {
const execMock = vi.spyOn(cp, "exec");
execMock.mockImplementationOnce(function (
this: cp.ChildProcess,
_cmd: string,
_opts: (ObjectEncodingOptions & cp.ExecOptions) | null | undefined,
callback?: ((error: ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => void) | undefined
): cp.ChildProcess {
if (callback) {
callback(null, "4.0.0", "");
}
@ -225,16 +191,20 @@ describe("funcCoreTools", () => {
});
it("should return the downloaded binary if there's no system binary", async () => {
const execMock = vi.spyOn(cp, 'exec');
execMock.mockImplementationOnce(function(this: cp.ChildProcess, _cmd: string, _opts: (ObjectEncodingOptions & cp.ExecOptions) | null | undefined, callback?: ((error: ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => void) | undefined): cp.ChildProcess {
const execMock = vi.spyOn(cp, "exec");
execMock.mockImplementationOnce(function (
this: cp.ChildProcess,
_cmd: string,
_opts: (ObjectEncodingOptions & cp.ExecOptions) | null | undefined,
callback?: ((error: ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => void) | undefined
): cp.ChildProcess {
if (callback) {
callback(null, "", "func does not exist");
}
return this;
});
vol.fromNestedJSON(
{
vol.fromNestedJSON({
["/home/user/.swa/core-tools/v4"]: { ".release-version": "4.3.2" },
});
@ -249,18 +219,21 @@ describe("funcCoreTools", () => {
});
it("should return the downloaded binary if the system binary is incompatible", async () => {
const execMock = vi.spyOn(cp, 'exec');
execMock.mockImplementationOnce(function(this: cp.ChildProcess, _cmd: string, _opts: (ObjectEncodingOptions & cp.ExecOptions) | null | undefined, callback?: ((error: ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => void) | undefined): cp.ChildProcess {
const execMock = vi.spyOn(cp, "exec");
execMock.mockImplementationOnce(function (
this: cp.ChildProcess,
_cmd: string,
_opts: (ObjectEncodingOptions & cp.ExecOptions) | null | undefined,
callback?: ((error: ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => void) | undefined
): cp.ChildProcess {
if (callback) {
callback(null, "3.0.0", "");
}
return this;
});
vol.fromNestedJSON(
{
vol.fromNestedJSON({
["/home/user/.swa/core-tools/v4"]: { ".release-version": "4.3.2" },
}
);
});
const binary = await getCoreToolsBinary();
// note: we have mocked os.platform(), so we can't check for os name!
@ -272,21 +245,20 @@ describe("funcCoreTools", () => {
});
it("should download core tools and return downloaded binary", async () => {
const execMock = vi.spyOn(cp, 'exec');
execMock.mockImplementationOnce(function(this: cp.ChildProcess, _cmd: string, _opts: (ObjectEncodingOptions & cp.ExecOptions) | null | undefined, callback?: ((error: ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => void) | undefined): cp.ChildProcess {
const execMock = vi.spyOn(cp, "exec");
execMock.mockImplementationOnce(function (
this: cp.ChildProcess,
_cmd: string,
_opts: (ObjectEncodingOptions & cp.ExecOptions) | null | undefined,
callback?: ((error: ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => void) | undefined
): cp.ChildProcess {
if (callback) {
callback(null, "", "func does not exist");
}
return this;
});
const fetchMock = vi.fn();
vi.mock("node-fetch", fetchMock);
fetchMock.mockImplementationOnce(() =>
Promise.resolve({
json: () =>
Promise.resolve({
mockResponse({
tags: {
v4: { release: "4.0.0" },
},
@ -303,16 +275,15 @@ describe("funcCoreTools", () => {
],
},
},
}),
})
);
});
const packageZip = Buffer.from("package");
fetchMock.mockImplementationOnce(() =>
Promise.resolve({
body: Readable.from(packageZip),
headers: new HeadersMock({ "content-length": packageZip.length.toString() }),
})
);
const packageResponse = new Response(packageZip.buffer, {
headers: {
"content-length": packageZip.length.toString(),
},
});
fetch.mockResolvedValue(packageResponse);
vol.fromNestedJSON({ ["/home/user/.swa/core-tools/"]: {} });
const binary = await getCoreToolsBinary();
@ -325,17 +296,20 @@ describe("funcCoreTools", () => {
});
it("should return undefined if an error occured", async () => {
const execMock = vi.spyOn(cp, 'exec');
execMock.mockImplementationOnce(function(this: cp.ChildProcess, _cmd: string, _opts: (ObjectEncodingOptions & cp.ExecOptions) | null | undefined, callback?: ((error: ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => void) | undefined): cp.ChildProcess {
const execMock = vi.spyOn(cp, "exec");
execMock.mockImplementationOnce(function (
this: cp.ChildProcess,
_cmd: string,
_opts: (ObjectEncodingOptions & cp.ExecOptions) | null | undefined,
callback?: ((error: ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => void) | undefined
): cp.ChildProcess {
if (callback) {
callback(null, "", "func does not exist");
}
return this;
});
const fetchMock = vi.fn();
vi.mock("node-fetch", fetchMock);
fetchMock.mockImplementationOnce(() => Promise.reject({}));
fetch.mockRejectedValueOnce({});
const binary = await getCoreToolsBinary();
expect(binary).toBe(undefined);
@ -344,20 +318,20 @@ describe("funcCoreTools", () => {
describe("downloadCoreTools", () => {
it("should throw an error if the download is corrupted", async () => {
const execMock = vi.spyOn(cp, 'exec');
execMock.mockImplementationOnce(function(this: cp.ChildProcess, _cmd: string, _opts: (ObjectEncodingOptions & cp.ExecOptions) | null | undefined, callback?: ((error: ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => void) | undefined): cp.ChildProcess {
const execMock = vi.spyOn(cp, "exec");
execMock.mockImplementationOnce(function (
this: cp.ChildProcess,
_cmd: string,
_opts: (ObjectEncodingOptions & cp.ExecOptions) | null | undefined,
callback?: ((error: ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => void) | undefined
): cp.ChildProcess {
if (callback) {
callback(null, "", "func does not exist");
}
return this;
});
const fetchMock = vi.fn();
vi.mock("node-fetch", fetchMock);
fetchMock.mockImplementationOnce(() =>
Promise.resolve({
json: () =>
Promise.resolve({
mockResponse({
tags: {
v4: { release: "4.0.0" },
},
@ -373,16 +347,15 @@ describe("funcCoreTools", () => {
],
},
},
}),
})
);
});
const packageZip = Buffer.from("package");
fetchMock.mockImplementationOnce(() =>
Promise.resolve({
body: Readable.from(packageZip),
headers: new HeadersMock({ "content-length": packageZip.length.toString() }),
})
);
const packageResponse = new Response(packageZip.buffer, {
headers: {
"content-length": packageZip.length.toString(),
},
});
fetch.mockResolvedValueOnce(packageResponse);
vol.fromNestedJSON({ ["/home/user/.swa/core-tools/"]: {} });
await expect(async () => await downloadCoreTools(4)).rejects.toThrowError(/SHA2 mismatch/);

Просмотреть файл

@ -1,12 +1,7 @@
import "../../tests/_mocks/fs.js";
import { fs, vol } from "memfs";
import { isGitProject, updateGitIgnore } from "./git.js";
vi.mock("node:fs");
vi.mock("node:fs/promises", async () => {
const memfs: { fs: typeof fs } = await vi.importActual("memfs");
return memfs.fs.promises;
});
describe("git", () => {
beforeEach(() => {
vol.reset();

Просмотреть файл

@ -1,18 +1,13 @@
import "../../../tests/_mocks/fs.js";
import { fs, vol } from "memfs";
import { logger } from "./logger.js";
import * as cliConfigModule from "./cli-config.js";
import { getConfigFileOptions, updateSwaCliConfigFile, writeConfigFile } from "./cli-config.js";
// Spy on console to avoid this error: https://github.com/tschaub/mock-fs/issues/234
vi.spyOn(global.console, "log").mockImplementation(() => {});
vi.spyOn(global.console, "warn").mockImplementation(() => {});
vi.spyOn(global.console, "error").mockImplementation(() => {});
const errorLogger = vi.fn();
vi.mock("../../core/utils/logger", () => {
vi.mock("./logger", () => {
return {
logger: {
error: errorLogger,
error: vi.fn(),
log: vi.fn(),
warn: vi.fn(),
silly: vi.fn(),
@ -21,13 +16,6 @@ vi.mock("../../core/utils/logger", () => {
};
});
vi.mock("node:fs");
vi.mock("node:fs/promises", async () => {
const memfs: { fs: typeof fs } = await vi.importActual("memfs");
return memfs.fs.promises;
});
const writeFileMock = vi.mocked("node:fs/promises.writeFile")
const mockConfig1 = {
$schema: "../../../schema/swa-cli.config.schema.json",
configurations: {
@ -63,49 +51,48 @@ const mockConfig2 = {
describe("CLI config", () => {
describe("getConfigFileOptions()", () => {
beforeEach(() => {
vol.reset();
});
it("Should return empty object if not found", async () => {
vol.fromJSON({
"swa-cli.config.json": JSON.stringify(mockConfig1)
"swa-cli.config.json": JSON.stringify(mockConfig1),
});
expect(await getConfigFileOptions("app", "")).toStrictEqual({});
});
it("Should return empty object if contex is undefined", async () => {
vol.fromJSON({
"swa-cli.config.json": JSON.stringify(mockConfig1)
"swa-cli.config.json": JSON.stringify(mockConfig1),
});
expect(await getConfigFileOptions(undefined, "")).toStrictEqual({});
});
it("Should return empty object if config name is not found", async () => {
vol.fromJSON({
"swa-cli.config.json": JSON.stringify(mockConfig1)
"swa-cli.config.json": JSON.stringify(mockConfig1),
});
expect(await getConfigFileOptions("configName", "swa-cli.config.json")).toStrictEqual({});
});
it("Should return proper config options", async () => {
vol.fromJSON({
"swa-cli.config.json": JSON.stringify(mockConfig1)
"swa-cli.config.json": JSON.stringify(mockConfig1),
});
expect(await getConfigFileOptions("app", "swa-cli.config.json")).toStrictEqual(mockConfig1.configurations.app);
});
it("Should return the default config if there are one or more configs", async () => {
vol.fromJSON({
"swa-cli.config.json": JSON.stringify(mockConfig1)
"swa-cli.config.json": JSON.stringify(mockConfig1),
});
expect(await getConfigFileOptions(undefined, "swa-cli.config.json")).toStrictEqual(mockConfig1.configurations.app);
});
it("Should return a default config", async () => {
vol.fromJSON({
"swa-cli.config.json": JSON.stringify(mockConfig2)
"swa-cli.config.json": JSON.stringify(mockConfig2),
});
expect(await getConfigFileOptions(undefined, "swa-cli.config.json")).toStrictEqual(mockConfig2.configurations.app);
});
@ -116,7 +103,7 @@ describe("CLI config", () => {
it("Should return proper config without path specified", async () => {
vol.fromJSON({
"swa-cli.config.json": JSON.stringify(mockConfig1)
"swa-cli.config.json": JSON.stringify(mockConfig1),
});
expect(await getConfigFileOptions("app", "swa-cli.config.json")).toStrictEqual(mockConfig1.configurations.app);
});
@ -151,6 +138,7 @@ describe("CLI config", () => {
// set currentSwaCliConfigFromFile to undefined
const spyGetCurrentSwaCliConfigFromFile = vi.spyOn(cliConfigModule, "getCurrentSwaCliConfigFromFile").mockReturnValue(undefined);
const spyWriteFile = vi.spyOn(fs, "writeFile");
const storedConfig = {
configurations: {
@ -160,13 +148,13 @@ describe("CLI config", () => {
},
};
vol.fromJSON({
"swa-cli.config.json": JSON.stringify(storedConfig)
"swa-cli.config.json": JSON.stringify(storedConfig),
});
await updateSwaCliConfigFile(config);
// we should not write to config file
expect(writeFileMock).not.toHaveBeenCalled();
expect(spyWriteFile).not.toHaveBeenCalled();
expect(spyGetCurrentSwaCliConfigFromFile).toHaveBeenCalled();
expect(logger.error).toHaveBeenCalledWith("No configuration file currently loaded", true);
});
@ -179,6 +167,7 @@ describe("CLI config", () => {
// set currentSwaCliConfigFromFile to undefined
const spyGetCurrentSwaCliConfigFromFile = vi.spyOn(cliConfigModule, "getCurrentSwaCliConfigFromFile").mockReturnValue({ name: "app" } as any);
const spyWriteFile = vi.spyOn(fs, "writeFile");
// const spyProcessExit = vi.spyOn(process, "exit").mockImplementation(() => {});
const mockConfig = {
@ -187,13 +176,13 @@ describe("CLI config", () => {
},
};
vol.fromJSON({
"swa-cli.config.json": JSON.stringify(mockConfig)
"swa-cli.config.json": JSON.stringify(mockConfig),
});
await updateSwaCliConfigFile(config);
expect(spyGetCurrentSwaCliConfigFromFile).toHaveBeenCalled();
expect(writeFileMock).toHaveBeenCalled();
expect(spyWriteFile).toHaveBeenCalled();
//expect(spyProcessExit).not.toHaveBeenCalled();
});
});
@ -216,15 +205,16 @@ describe("CLI config", () => {
},
};
vol.fromJSON({
"swa-cli.config.json": JSON.stringify(mockConfig)
"swa-cli.config.json": JSON.stringify(mockConfig),
});
const spyWriteFile = vi.spyOn(fs, "writeFile");
await writeConfigFile("swa-cli.config.json", "foo", config);
const savedFileContent = fs.readFileSync("swa-cli.config.json", "utf8");
expect(writeFileMock).toHaveBeenCalled();
expect(spyWriteFile).toHaveBeenCalled();
expect(spySwaCliConfigFileExists).toHaveBeenCalled();
expect(JSON.parse('' + savedFileContent).configurations.foo).toStrictEqual(config);
expect(JSON.parse("" + savedFileContent).configurations.foo).toStrictEqual(config);
});
it("Should override existing config into file", async () => {
@ -240,15 +230,16 @@ describe("CLI config", () => {
},
};
vol.fromJSON({
"swa-cli.config.json": JSON.stringify(mockConfig)
"swa-cli.config.json": JSON.stringify(mockConfig),
});
const spyWriteFile = vi.spyOn(fs, "writeFile");
await writeConfigFile("swa-cli.config.json", "app", config);
const savedFileContent = fs.readFileSync("swa-cli.config.json", "utf8");
expect(writeFileMock).toHaveBeenCalled();
expect(spyWriteFile).toHaveBeenCalled();
expect(spySwaCliConfigFileExists).toHaveBeenCalled();
expect(JSON.parse('' + savedFileContent).configurations.app).toStrictEqual(config);
expect(JSON.parse("" + savedFileContent).configurations.app).toStrictEqual(config);
});
it("Should add an configuration entry if it does not exist", async () => {
@ -259,15 +250,16 @@ describe("CLI config", () => {
};
vol.fromJSON({
"swa-cli.config.json": "{}"
"swa-cli.config.json": "{}",
});
const spyWriteFile = vi.spyOn(fs, "writeFile");
await writeConfigFile("swa-cli.config.json", "app", config);
const savedFileContent = fs.readFileSync("swa-cli.config.json", "utf8");
expect(writeFileMock).toHaveBeenCalled();
expect(spyWriteFile).toHaveBeenCalled();
expect(spySwaCliConfigFileExists).toHaveBeenCalled();
expect(JSON.parse('' + savedFileContent).configurations.app).toStrictEqual(config);
expect(JSON.parse("" + savedFileContent).configurations.app).toStrictEqual(config);
});
it("Should error if config file is malformed", async () => {
@ -277,12 +269,11 @@ describe("CLI config", () => {
};
vol.fromJSON({
"swa-cli.config.json": "\"\""
"swa-cli.config.json": '""',
});
await writeConfigFile("swa-cli.config.json", "app", config);
expect(errorLogger).toHaveBeenCalled();
expect(logger.error).toHaveBeenCalled();
});
});
});

Просмотреть файл

@ -1,6 +1,9 @@
vi.mock("../constants", () => {});
import mockFs from "mock-fs";
import "../../../tests/_mocks/fs.js";
vi.mock("../constants", () => {
return {};
});
import path from "node:path";
import { vol } from "memfs";
import { argv, createStartupScriptCommand, parseServerTimeout } from "./cli.js";
import { logger } from "./logger.js";
@ -112,11 +115,11 @@ describe("createStartupScriptCommand()", () => {
});
});
describe("an external script", () => {
afterEach(() => {
mockFs.restore();
beforeEach(() => {
vol.reset();
});
it("should parse relative script file ./script.sh", () => {
mockFs({
vol.fromJSON({
"script.sh": "",
});
const cmd = createStartupScriptCommand("script.sh", {});
@ -124,15 +127,15 @@ describe("createStartupScriptCommand()", () => {
});
it("should parse relative script file ./script.sh from the root of --app-location", () => {
mockFs({
vol.fromJSON({
"/bar/script.sh": "",
});
const cmd = createStartupScriptCommand("script.sh", { appLocation: `${path.sep}bar` });
expect(cmd).toInclude(path.join(path.sep, "bar", "script.sh"));
expect(cmd).to.include(path.join(path.sep, "bar", "script.sh"));
});
it("should parse absolute script file /foo/script.sh", () => {
mockFs({
vol.fromNestedJSON({
"/foo": {
"script.sh": "",
},

Просмотреть файл

@ -1,8 +1,11 @@
vi.mock("./logger", () => {
return {
logger: {
silly: vi.fn();
}
silly: vi.fn(),
},
};
});
import { validateCookie } from "./cookie.js";
describe("validateCookie()", () => {

Просмотреть файл

@ -1,4 +1,6 @@
vi.mock("../constants", () => {});
vi.mock("../constants", () => {
return {};
});
import { logger } from "./logger.js";
import { address, hostnameToIpAdress, isHttpsUrl, parsePort, parseUrl, response } from "./net.js";
@ -313,19 +315,19 @@ describe("net utilities", () => {
describe("isHttpsUrl()", () => {
it("https url should be valid", () => {
expect(isHttpsUrl("https://foo.com")).toBeTrue();
expect(isHttpsUrl("https://foo.com")).to.be.true;
});
it("http url should be invalid", () => {
expect(isHttpsUrl("http://foo.com")).toBeFalse();
expect(isHttpsUrl("http://foo.com")).to.be.false;
});
it("empty url should be invalid", () => {
expect(isHttpsUrl(undefined)).toBeFalse();
expect(isHttpsUrl(undefined)).to.be.false;
});
it("wrong Url should be invalid", () => {
expect(isHttpsUrl("foo.com")).toBeFalse();
expect(isHttpsUrl("foo.com")).to.be.false;
});
it("url should not be case sensitive", () => {
expect(isHttpsUrl("HTTPS://foo.com")).toBeTrue();
expect(isHttpsUrl("HTTPS://foo.com")).to.be.true;
});
});
});

Просмотреть файл

@ -1,17 +1,12 @@
import "../../../tests/_mocks/fs.js";
import { Command } from "commander";
import { fs, vol } from "memfs";
import { vol } from "memfs";
import { swaCliConfigFilename } from "./cli-config.js";
import { parsePort } from "./net.js";
import { parseServerTimeout } from "./cli.js";
import { configureOptions, getUserOptions } from "./options.js";
import { DEFAULT_CONFIG } from "../../config.js";
vi.mock("node:fs");
vi.mock("node:fs/promises", async () => {
const memfs: { fs: typeof fs } = await vi.importActual("memfs");
return memfs.fs.promises;
});
describe("configureOptions()", () => {
beforeEach(() => {
vol.reset();

Просмотреть файл

@ -1,18 +1,12 @@
import "../../../tests/_mocks/fs.js";
import { vol } from "memfs";
import path from "node:path";
import { findSWAConfigFile, traverseFolder } from "./user-config.js";
import { logger } from "./logger.js";
import { fs, vol } from "memfs";
vi.mock("node:fs");
vi.mock("node:fs/promises", async () => {
const memfs: { fs: typeof fs } = await vi.importActual("memfs");
return memfs.fs.promises;
});
vi.spyOn(logger, "silly").mockImplementation(() => {});
vi.spyOn(logger, "warn").mockImplementation(() => {});
import path from "node:path";
import { findSWAConfigFile, traverseFolder } from "./user-config.js";
describe("userConfig", () => {
describe("traverseFolder()", () => {
beforeEach(() => {

Просмотреть файл

@ -1,5 +1,10 @@
vi.mock("../constants", () => {});
import mockFs from "mock-fs";
import "../../../tests/_mocks/fs.js";
import { vol } from "memfs";
vi.mock("../constants", () => {
return {};
});
import path from "path";
import { MockInstance } from "vitest";
import { convertToNativePaths } from "../../test.helpers.js";
@ -24,7 +29,7 @@ describe("readWorkflowFile()", () => {
});
afterEach(() => {
mockFs.restore();
vol.reset();
processSpy.mockRestore();
});
@ -33,7 +38,7 @@ describe("readWorkflowFile()", () => {
});
it("config file with wrong filename should return undefined", () => {
mockFs({
vol.fromJSON({
[convertToNativePaths("/ABSOLUTE_PATH/.github/workflows/wrong-file-name-pattern.yml")]: "",
});
@ -41,7 +46,7 @@ describe("readWorkflowFile()", () => {
});
it("invalid YAML file should throw", () => {
mockFs({
vol.fromJSON({
[convertToNativePaths("/ABSOLUTE_PATH/.github/workflows/azure-static-web-apps__not-valid.yml")]: "",
});
@ -50,7 +55,7 @@ describe("readWorkflowFile()", () => {
describe("checking workflow properties", () => {
it(`missing property "jobs" should throw`, () => {
mockFs({
vol.fromJSON({
[convertToNativePaths("/ABSOLUTE_PATH/.github/workflows/azure-static-web-apps__not-valid.yml")]: `name: Azure Static Web Apps CI/CD`,
});
@ -58,7 +63,7 @@ describe("readWorkflowFile()", () => {
});
it(`missing property "jobs.build_and_deploy_job" should throw`, () => {
mockFs({
vol.fromJSON({
[convertToNativePaths("/ABSOLUTE_PATH/.github/workflows/azure-static-web-apps.yml")]: `
jobs:
invalid_property:
@ -68,7 +73,7 @@ jobs:
});
it(`missing property "jobs.build_and_deploy_job.steps" should throw`, () => {
mockFs({
vol.fromJSON({
[convertToNativePaths("/ABSOLUTE_PATH/.github/workflows/azure-static-web-apps.yml")]: `
jobs:
build_and_deploy_job:
@ -80,7 +85,7 @@ jobs:
});
it(`invalid property"jobs.build_and_deploy_job.steps" should throw`, () => {
mockFs({
vol.fromJSON({
[convertToNativePaths("/ABSOLUTE_PATH/.github/workflows/azure-static-web-apps.yml")]: `
jobs:
build_and_deploy_job:
@ -91,7 +96,7 @@ jobs:
});
it(`invalid property "jobs.build_and_deploy_job.steps[]" should throw`, () => {
mockFs({
vol.fromJSON({
[convertToNativePaths("/ABSOLUTE_PATH/.github/workflows/azure-static-web-apps.yml")]: `
jobs:
build_and_deploy_job:
@ -104,7 +109,7 @@ jobs:
});
it(`missing property "jobs.build_and_deploy_job.steps[].with" should throw`, () => {
mockFs({
vol.fromJSON({
[convertToNativePaths("/ABSOLUTE_PATH/.github/workflows/azure-static-web-apps.yml")]: `
jobs:
build_and_deploy_job:
@ -120,7 +125,7 @@ jobs:
describe("checking SWA properties", () => {
it("property 'app_location' should be set", () => {
mockFs({
vol.fromJSON({
[convertToNativePaths("/ABSOLUTE_PATH/.github/workflows/azure-static-web-apps.yml")]: `
jobs:
build_and_deploy_job:
@ -139,7 +144,7 @@ jobs:
});
it("property 'app_location' should be set to '/' if missing", () => {
mockFs({
vol.fromJSON({
[convertToNativePaths("/ABSOLUTE_PATH/.github/workflows/azure-static-web-apps.yml")]: `
jobs:
build_and_deploy_job:
@ -158,7 +163,7 @@ jobs:
});
it("property 'api_location' should be set", () => {
mockFs({
vol.fromJSON({
[convertToNativePaths("/ABSOLUTE_PATH/.github/workflows/azure-static-web-apps.yml")]: `
jobs:
build_and_deploy_job:
@ -177,7 +182,7 @@ jobs:
});
it("property 'api_location' should be undefined if missing", () => {
mockFs({
vol.fromJSON({
[convertToNativePaths("/ABSOLUTE_PATH/.github/workflows/azure-static-web-apps.yml")]: `
jobs:
build_and_deploy_job:
@ -196,7 +201,7 @@ jobs:
});
it("property 'output_location' should be set", () => {
mockFs({
vol.fromJSON({
[convertToNativePaths("/ABSOLUTE_PATH/.github/workflows/azure-static-web-apps.yml")]: `
jobs:
build_and_deploy_job:
@ -215,7 +220,7 @@ jobs:
});
it("property 'output_location' should be set to default if missing", () => {
mockFs({
vol.fromJSON({
[convertToNativePaths("/ABSOLUTE_PATH/.github/workflows/azure-static-web-apps.yml")]: `
jobs:
build_and_deploy_job:
@ -234,7 +239,7 @@ jobs:
});
it("property 'app_build_command' should be set", () => {
mockFs({
vol.fromJSON({
[convertToNativePaths("/ABSOLUTE_PATH/.github/workflows/azure-static-web-apps.yml")]: `
jobs:
build_and_deploy_job:
@ -253,7 +258,7 @@ jobs:
});
it("property 'app_build_command' should be set to default if missing", () => {
mockFs({
vol.fromJSON({
[convertToNativePaths("/ABSOLUTE_PATH/.github/workflows/azure-static-web-apps.yml")]: `
jobs:
build_and_deploy_job:
@ -272,7 +277,7 @@ jobs:
});
it("property 'api_build_command' should be set", () => {
mockFs({
vol.fromJSON({
[convertToNativePaths("/ABSOLUTE_PATH/.github/workflows/azure-static-web-apps.yml")]: `
jobs:
build_and_deploy_job:
@ -291,7 +296,7 @@ jobs:
});
it("property 'api_build_command' should be set to default if missing", () => {
mockFs({
vol.fromJSON({
[convertToNativePaths("/ABSOLUTE_PATH/.github/workflows/azure-static-web-apps.yml")]: `
jobs:
build_and_deploy_job:

Просмотреть файл

@ -1,4 +1,7 @@
vi.mock("../../../core/constants", () => {});
vi.mock("../../../core/constants", () => {
return {};
});
import { mimeTypes } from "./mime-types.js";
describe("mimeTypes()", () => {

Просмотреть файл

@ -1,5 +1,8 @@
vi.mock("../../../core/constants", () => {});
import mockFs from "mock-fs";
import "../../../../tests/_mocks/fs.js";
import { vol } from "memfs";
vi.mock("../../../core/constants", () => {
return {};
});
import { navigationFallback } from "./navigation-fallback.js";
@ -7,14 +10,12 @@ describe("navigationFallback()", () => {
let req: any;
let res: any;
let userConfig: SWAConfigFileNavigationFallback;
beforeEach(() => {
req = {} as any;
res = {} as any;
userConfig = {} as any;
});
afterEach(() => {
mockFs.restore();
vol.reset();
});
it("should not process fallbacks if empty config", () => {
@ -60,7 +61,7 @@ describe("navigationFallback()", () => {
};
process.env.SWA_CLI_OUTPUT_LOCATION = "/";
mockFs({
vol.fromNestedJSON({
"/images/foo.png": "",
});
@ -77,7 +78,7 @@ describe("navigationFallback()", () => {
};
process.env.SWA_CLI_OUTPUT_LOCATION = "/";
mockFs({
vol.fromNestedJSON({
"/no-file": "",
});
@ -94,7 +95,7 @@ describe("navigationFallback()", () => {
};
process.env.SWA_CLI_OUTPUT_LOCATION = "/";
mockFs({
vol.fromNestedJSON({
"/images/foo.png": "",
});
@ -111,7 +112,7 @@ describe("navigationFallback()", () => {
};
process.env.SWA_CLI_OUTPUT_LOCATION = "/";
mockFs({
vol.fromNestedJSON({
"/no-file": "",
});
@ -128,7 +129,7 @@ describe("navigationFallback()", () => {
};
process.env.SWA_CLI_OUTPUT_LOCATION = "/";
mockFs({
vol.fromNestedJSON({
"/no-file": "",
});
@ -145,7 +146,7 @@ describe("navigationFallback()", () => {
};
process.env.SWA_CLI_OUTPUT_LOCATION = "/";
mockFs({
vol.fromNestedJSON({
"/no-file": "",
});

Просмотреть файл

@ -1,10 +1,15 @@
vi.mock("../../../core/utils/logger", () => {
return {
logger: {
silly: () => {},
},
};
});
import "../../../../tests/_mocks/fs.js";
import { vol } from "memfs";
import type http from "node:http";
import { MockInstance } from "vitest";
import { applyRedirectResponse, isRequestMethodValid, isRouteRequiringUserRolesCheck, tryFindFileForRequest, tryGetMatchingRoute } from "./routes.js";
import { logger } from "../../../core/utils/logger.js";
import * as routeModule from "../route-processor.js";
import * as cookieModule from "../../../core/utils/cookie.js";
vi.spyOn(logger, "silly").mockImplementation(() => {});
vi.mock("../../../core/constants", () => {
return {
SWA_CLI_OUTPUT_LOCATION: "/",
@ -25,26 +30,18 @@ vi.mock("../../../config", () => {
};
});
import type http from "node:http";
import mockFs from "mock-fs";
import { MockInstance } from "vitest";
import { applyRedirectResponse, isRequestMethodValid, isRouteRequiringUserRolesCheck, tryFindFileForRequest, tryGetMatchingRoute } from "./routes.js";
import * as routeModule from "../route-processor.js";
import * as cookieModule from "../../../core/utils/cookie.js";
// btoa is only available in Node.js >= 16
const btoa = (str: string) => Buffer.from(str).toString("base64");
describe("route utilities", () => {
describe("route", () => {
describe("tryFindFileForRequest()", () => {
afterEach(() => {
mockFs.restore();
beforeEach(() => {
vol.reset();
});
it("should return NULL when file doesn't exist", () => {
mockFs({
vol.fromJSON({
"/bar.txt": "",
});
@ -53,7 +50,7 @@ describe("route utilities", () => {
});
it("should return file path when file exists", () => {
mockFs({
vol.fromJSON({
"/foo.png": "",
});
@ -62,7 +59,7 @@ describe("route utilities", () => {
});
it("should return file path when file (without extension) exists", () => {
mockFs({
vol.fromJSON({
"/foo": "",
});
@ -71,7 +68,7 @@ describe("route utilities", () => {
});
it("should return NULL when file (without extension) doesn't exist", () => {
mockFs({
vol.fromJSON({
"/foo.txt": "",
});
@ -80,7 +77,7 @@ describe("route utilities", () => {
});
it("should return file path when file (w/ space) exists", () => {
mockFs({
vol.fromJSON({
"/foo bar.png": "",
});
@ -89,7 +86,7 @@ describe("route utilities", () => {
});
it("should return file path when file (w/ percent-encoded symbols) exists", () => {
mockFs({
vol.fromJSON({
"/with space.html": "",
});
@ -98,7 +95,7 @@ describe("route utilities", () => {
});
it("should return file path when file exists in subfolder", () => {
mockFs({
vol.fromJSON({
"/foo/bar.png": "",
});
@ -107,7 +104,7 @@ describe("route utilities", () => {
});
it("should return file path when file exists in subfolder (w/ percent-encoded symbols)", () => {
mockFs({
vol.fromJSON({
"/with space/index.html": "",
});
@ -116,7 +113,7 @@ describe("route utilities", () => {
});
it("should return null when index.html does not exist", () => {
mockFs({
vol.fromNestedJSON({
"/foo": {
"foo.html": "",
},
@ -127,7 +124,7 @@ describe("route utilities", () => {
});
it("should return index.html when folder is provided", () => {
mockFs({
vol.fromNestedJSON({
"/foo": {
"index.html": "",
},
@ -138,7 +135,7 @@ describe("route utilities", () => {
});
it("should return same file if using dev server", async () => {
mockFs({
vol.fromNestedJSON({
"/foo": {
"index.html": "",
},
@ -284,8 +281,25 @@ describe("route utilities", () => {
},
],
};
let spyDoesRequestPathMatchRoute: MockInstance<(this: boolean | undefined, requestPath: string, routeRule: SWAConfigFileRoute | undefined, requestMethod: string | null | undefined, methods: string[] | null | undefined, authStatus: number) => boolean | undefined>;
let spyDoesRequestPathMatchLegacyRoute: MockInstance<(this: boolean | undefined, requestPath: string, routeRule: SWAConfigFileRoute | undefined, isAuthRequest: boolean, isFileRequest: boolean) => boolean | undefined>;
let spyDoesRequestPathMatchRoute: MockInstance<
(
this: boolean | undefined,
requestPath: string,
routeRule: SWAConfigFileRoute | undefined,
requestMethod: string | null | undefined,
methods: string[] | null | undefined,
authStatus: number
) => boolean | undefined
>;
let spyDoesRequestPathMatchLegacyRoute: MockInstance<
(
this: boolean | undefined,
requestPath: string,
routeRule: SWAConfigFileRoute | undefined,
isAuthRequest: boolean,
isFileRequest: boolean
) => boolean | undefined
>;
beforeEach(() => {
spyDoesRequestPathMatchRoute = vi.spyOn(routeModule, "doesRequestPathMatchRoute");
spyDoesRequestPathMatchLegacyRoute = vi.spyOn(routeModule, "doesRequestPathMatchLegacyRoute");

10
tests/_mocks/fetch.js Normal file
Просмотреть файл

@ -0,0 +1,10 @@
// See https://stackoverflow.com/questions/75756917/how-to-mock-the-response-of-node-fetch-in-typescript-using-suoertest-and-vitest
import { vi } from "vitest";
vi.mock("node-fetch", async () => {
const actual = await vi.importActual("node-fetch");
return {
...actual,
default: vi.fn(),
};
});