Skip to content

Commit

Permalink
fix tests and add new files
Browse files Browse the repository at this point in the history
  • Loading branch information
Ben Loe committed Apr 15, 2024
1 parent 77778fd commit e193a7f
Show file tree
Hide file tree
Showing 11 changed files with 308 additions and 51 deletions.
6 changes: 0 additions & 6 deletions src/background/performConfiguredRequest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import { hasSpecificErrorCause } from "@/errors/errorHelpers";
import { InteractiveLoginRequiredError } from "@/errors/authErrors";
import { deserializeError, serializeError } from "serialize-error";
import { type NetworkRequestConfig } from "@/types/networkTypes";
import { pixiebrixConfigurationFactory } from "@/integrations/util/pixiebrixConfigurationFactory";

// Disable automatic __mocks__ resolution #6799
jest.mock("@/data/service/apiClient", () =>
Expand Down Expand Up @@ -70,11 +69,6 @@ jest.mock("@/background/auth/getToken", () => ({
jest.mock("@/auth/authStorage");
jest.mock("@/integrations/locator");

// Use real version of pixiebrixConfigurationFactory
(pixiebrixConfigurationFactory as any) = jest.requireActual(
"@/integrations/locator",
).pixiebrixConfigurationFactory;

enrichAxiosErrors();

afterEach(() => {
Expand Down
2 changes: 1 addition & 1 deletion src/background/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ async function proxyRequest<T>(
}

const authenticatedRequestConfig = await authenticate(
await pixiebrixConfigurationFactory(),
pixiebrixConfigurationFactory(),
{
url: await absoluteApiUrl("/api/proxy/"),
method: "post" as Method,
Expand Down
2 changes: 1 addition & 1 deletion src/contrib/zapier/PushOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ function useHooks(): AsyncState<Webhook[]> {
return useAsyncState(async () => {
const { data } = await getPlatform().request<{
new_push_fields: Webhook[];
}>(await pixiebrixConfigurationFactory(), {
}>(pixiebrixConfigurationFactory(), {
url: await absoluteApiUrl("/api/webhooks/hooks/"),
method: "get",
});
Expand Down
2 changes: 1 addition & 1 deletion src/contrib/zapier/push.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export class PushZap extends EffectABC {
): Promise<void> {
const { data: webhooks } = await options.platform.request<{
new_push_fields: Webhook[];
}>(await pixiebrixConfigurationFactory(), {
}>(pixiebrixConfigurationFactory(), {
url: await absoluteApiUrl("/api/webhooks/hooks/"),
method: "get",
});
Expand Down
4 changes: 2 additions & 2 deletions src/integrations/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import { type RegistryId } from "@/types/registryTypes";
import { validateRegistryId } from "@/types/helpers";
import type { UUID } from "@/types/stringTypes";
import { uuidSequence } from "@/testUtils/factories/stringFactories";
import type { OutputKey } from "@/types/runtimeTypes";
import { type Schema } from "@/types/schemaTypes";
import { validateOutputKey } from "@/runtime/runtimeTypes";

/**
* The PixieBrix API integration definition registry id.
Expand All @@ -29,7 +29,7 @@ export const PIXIEBRIX_INTEGRATION_ID: RegistryId =
validateRegistryId("@pixiebrix/api");
// Use a minimal valid UUID for pixiebrix to avoid null id
export const PIXIEBRIX_INTEGRATION_CONFIG_ID: UUID = uuidSequence(0);
export const PIXIEBRIX_OUTPUT_KEY = "pixiebrix" as OutputKey;
export const PIXIEBRIX_OUTPUT_KEY = validateOutputKey("pixiebrix");
// We should probably leave this as called "SERVICES_" until if/when the actual url is changed
// to point to /schemas/integrations/, just as a reminder
export const SERVICES_BASE_SCHEMA_URL =
Expand Down
2 changes: 1 addition & 1 deletion src/integrations/locator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ class LazyLocatorFactory {

if (serviceId === PIXIEBRIX_INTEGRATION_ID) {
// HACK: for now use the separate storage for the extension key
return [await pixiebrixConfigurationFactory()];
return [pixiebrixConfigurationFactory()];
}

let service: IntegrationABC;
Expand Down
100 changes: 100 additions & 0 deletions src/integrations/util/makeIntegrationsContextFromDependencies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright (C) 2024 PixieBrix, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

/* eslint-disable security/detect-object-injection -- multiple places use the same constructed key value, not user input */

import { type IntegrationDependency } from "@/integrations/integrationTypes";
import {
type IntegrationDependencyVarRef,
type IntegrationsContext,
type IntegrationsContextValue,
} from "@/types/runtimeTypes";
import locateSanitizedIntegrationConfigWithRetry from "@/integrations/util/locateSanitizedIntegrationConfigWithRetry";
import { pickBy } from "lodash";
import { type UUID } from "@/types/stringTypes";
import { type RegistryId } from "@/types/registryTypes";
import { type Nullishable } from "@/utils/nullishUtils";
import { PIXIEBRIX_INTEGRATION_ID } from "@/integrations/constants";
import { NotConfiguredError } from "@/errors/businessErrors";
import { pixiebrixConfigurationFactory } from "@/integrations/util/pixiebrixConfigurationFactory";

async function dependencyContextValue({
integrationId,
configId,
}: {
integrationId: RegistryId;
configId: UUID;
}): Promise<IntegrationsContextValue> {
// Should be safe to call locateWithRetry in parallel b/c the locator.refresh() method debounces/coalesces
// the promise
const integrationConfig = await locateSanitizedIntegrationConfigWithRetry(
integrationId,
configId,
);
return {
...pickBy(
integrationConfig.config,
// Our JSON validator gets mad at undefined values, and we don't want to include the type brand
(value, key) => value !== undefined && key !== "_sanitizedConfigBrand",
),
__service: integrationConfig,
};
}

/** Build the integrations context by locating the dependencies */
export default async function makeIntegrationsContextFromDependencies(
// `ModComponentBase.integrationDependencies` is an optional field. Since we don't have strict-nullness checking on, calls to this method
// are error-prone. So just be defensive in the signature
// https://github.com/pixiebrix/pixiebrix-extension/issues/3262
dependencies: Nullishable<IntegrationDependency[]>,
): Promise<IntegrationsContext> {
const context: IntegrationsContext = {};

if (dependencies == null || dependencies.length === 0) {
return context;
}

for (const dependency of dependencies) {
const varRef = `@${dependency.outputKey}` as IntegrationDependencyVarRef;

if (dependency.integrationId === PIXIEBRIX_INTEGRATION_ID) {
context[varRef] = {
__service: pixiebrixConfigurationFactory(),
};
continue;
}

if (!dependency.configId) {
if (dependency.isOptional) {
context[varRef] = null;
}

throw new NotConfiguredError(
`No configuration selected for ${dependency.integrationId}`,
dependency.integrationId,
);
}

// eslint-disable-next-line no-await-in-loop -- We need to serialize these calls, because they will attempt to refresh the locator services cache
context[varRef] = await dependencyContextValue({
integrationId: dependency.integrationId,
configId: dependency.configId,
});
}

return context;
}
35 changes: 35 additions & 0 deletions src/integrations/util/pixiebrixConfigurationFactory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2024 PixieBrix, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import type {
SanitizedConfig,
SanitizedIntegrationConfig,
} from "@/integrations/integrationTypes";
import {
PIXIEBRIX_INTEGRATION_CONFIG_ID,
PIXIEBRIX_INTEGRATION_ID,
} from "@/integrations/constants";

export function pixiebrixConfigurationFactory(): SanitizedIntegrationConfig {
return {
id: PIXIEBRIX_INTEGRATION_CONFIG_ID,
serviceId: PIXIEBRIX_INTEGRATION_ID,
// Don't need to proxy requests to our own service
proxy: false,
config: {} as SanitizedConfig,
} as SanitizedIntegrationConfig;
}
33 changes: 33 additions & 0 deletions src/integrations/util/pixiebrixIntegrationDependencyFactory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2024 PixieBrix, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { type IntegrationDependency } from "@/integrations/integrationTypes";
import {
PIXIEBRIX_INTEGRATION_CONFIG_ID,
PIXIEBRIX_INTEGRATION_ID,
PIXIEBRIX_OUTPUT_KEY,
} from "@/integrations/constants";

export default function pixiebrixIntegrationDependencyFactory(): IntegrationDependency {
return {
integrationId: PIXIEBRIX_INTEGRATION_ID,
outputKey: PIXIEBRIX_OUTPUT_KEY,
isOptional: false,
apiVersion: "v2",
configId: PIXIEBRIX_INTEGRATION_CONFIG_ID,
} as IntegrationDependency;
}
16 changes: 16 additions & 0 deletions src/pageEditor/fields/DatabaseCommonOptions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*

Check failure on line 1 in src/pageEditor/fields/DatabaseCommonOptions.tsx

View workflow job for this annotation

GitHub Actions / strictNullChecks

strictNullChecks

src/pageEditor/fields/DatabaseCommonOptions.tsx was not found in tsconfig.strictNullChecks.json
* Copyright (C) 2024 PixieBrix, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
Loading

0 comments on commit e193a7f

Please sign in to comment.