
* Change process-async-saleor-webhook to process-saleor-webhook and add better debug logs * Change processWebhook name * wip * Add base class structure * refactor * add sync payload builder * wip * wip * Add some missing webhook responses * Fix tests for Async version * Fix tests * Add MockAPL test util * Refactor tests to use MockAPL * Add test to sync webhook * Restore legacy subscriptionQueryAst field for compatibility * CR Fixes - TS type & event -> eventType * Changelog, docs and remove old payment webhooks * Apply suggestions from code review Co-authored-by: Krzysztof Wolski <krzysztof.k.wolski@gmail.com> * Update src/handlers/next/saleor-webhooks/process-saleor-webhook.ts Co-authored-by: Krzysztof Wolski <krzysztof.k.wolski@gmail.com> --------- Co-authored-by: Krzysztof Wolski <krzysztof.k.wolski@gmail.com>
258 lines
8.3 KiB
TypeScript
258 lines
8.3 KiB
TypeScript
import { createMocks } from "node-mocks-http";
|
|
import { beforeEach, describe, expect, it, Mock, vi } from "vitest";
|
|
|
|
import { APL, AuthData } from "../../APL";
|
|
import { MockAPL } from "../../test-utils/mock-apl";
|
|
import { createAppRegisterHandler } from "./create-app-register-handler";
|
|
|
|
const mockJwksValue = "{}";
|
|
const mockAppId = "42";
|
|
|
|
vi.mock("../../get-app-id", () => ({
|
|
getAppId: vi.fn().mockResolvedValue("42"), // can't use var reference, due to hoisting
|
|
}));
|
|
|
|
vi.mock("../../fetch-remote-jwks", () => ({
|
|
fetchRemoteJwks: vi.fn().mockResolvedValue("{}"), // can't use var reference, due to hoisting
|
|
}));
|
|
|
|
describe("create-app-register-handler", () => {
|
|
let mockApl: APL;
|
|
|
|
beforeEach(() => {
|
|
mockApl = new MockAPL();
|
|
});
|
|
|
|
it("Sets auth data for correct request", async () => {
|
|
const { res, req } = createMocks({
|
|
/**
|
|
* Use body, instead of params, otherwise - for some reason - param is not accessible in mock request
|
|
* Maybe this is a bug https://github.com/howardabrams/node-mocks-http/blob/master/lib/mockRequest.js
|
|
*/
|
|
body: {
|
|
auth_token: "mock-auth-token",
|
|
},
|
|
headers: {
|
|
host: "some-saleor-host.cloud",
|
|
"x-forwarded-proto": "https",
|
|
"saleor-api-url": "https://mock-saleor-domain.saleor.cloud/graphql/",
|
|
"saleor-domain": "https://mock-saleor-domain.saleor.cloud/",
|
|
},
|
|
method: "POST",
|
|
});
|
|
|
|
const handler = createAppRegisterHandler({
|
|
apl: mockApl,
|
|
});
|
|
|
|
await handler(req, res);
|
|
|
|
/**
|
|
* It fails -> params.auth_token isn't present
|
|
*/
|
|
expect(mockApl.set).toHaveBeenCalledWith({
|
|
saleorApiUrl: "https://mock-saleor-domain.saleor.cloud/graphql/",
|
|
domain: "https://mock-saleor-domain.saleor.cloud/",
|
|
token: "mock-auth-token",
|
|
appId: "42",
|
|
jwks: "{}",
|
|
});
|
|
});
|
|
|
|
it("Returns 403 if configured to work only for specific saleor URL and try to install on prohibited one", async () => {
|
|
const { res, req } = createMocks({
|
|
/**
|
|
* Use body, instead of params, otherwise - for some reason - param is not accessible in mock request
|
|
* Maybe this is a bug https://github.com/howardabrams/node-mocks-http/blob/master/lib/mockRequest.js
|
|
*/
|
|
body: {
|
|
auth_token: "mock-auth-token",
|
|
},
|
|
headers: {
|
|
host: "some-saleor-host.cloud",
|
|
"x-forwarded-proto": "https",
|
|
"saleor-api-url": "https://wrong-saleor-domain.saleor.cloud/graphql/",
|
|
"saleor-domain": "https://wrong-saleor-domain.saleor.cloud/",
|
|
},
|
|
method: "POST",
|
|
});
|
|
|
|
const handler = createAppRegisterHandler({
|
|
apl: mockApl,
|
|
allowedSaleorUrls: [(url: string) => url === "https://mock-saleor-domain.saleor.cloud"],
|
|
});
|
|
|
|
await handler(req, res);
|
|
|
|
expect(res._getStatusCode()).toBe(403);
|
|
expect(res._getData().success).toBe(false);
|
|
});
|
|
|
|
describe("Callback hooks", () => {
|
|
it("Runs callback hooks - successful saving to APL scenario", async () => {
|
|
const mockOnRequestStart = vi.fn();
|
|
const mockOnRequestVerified = vi.fn();
|
|
const mockOnAuthAplFailed = vi.fn();
|
|
const mockOnAuthAplSaved = vi.fn();
|
|
|
|
const { res, req } = createMocks({
|
|
/**
|
|
* Use body, instead of params, otherwise - for some reason - param is not accessible in mock request
|
|
* Maybe this is a bug https://github.com/howardabrams/node-mocks-http/blob/master/lib/mockRequest.js
|
|
*/
|
|
body: {
|
|
auth_token: "mock-auth-token",
|
|
},
|
|
headers: {
|
|
host: "some-saleor-host.cloud",
|
|
"x-forwarded-proto": "https",
|
|
"saleor-api-url": "https://mock-saleor-domain.saleor.cloud/graphql/",
|
|
"saleor-domain": "https://mock-saleor-domain.saleor.cloud/",
|
|
},
|
|
method: "POST",
|
|
});
|
|
|
|
const handler = createAppRegisterHandler({
|
|
apl: mockApl,
|
|
onRequestStart: mockOnRequestStart,
|
|
onRequestVerified: mockOnRequestVerified,
|
|
onAplSetFailed: mockOnAuthAplFailed,
|
|
onAuthAplSaved: mockOnAuthAplSaved,
|
|
});
|
|
|
|
const expectedAuthData: AuthData = {
|
|
token: "mock-auth-token",
|
|
domain: "https://mock-saleor-domain.saleor.cloud/",
|
|
saleorApiUrl: "https://mock-saleor-domain.saleor.cloud/graphql/",
|
|
jwks: mockJwksValue,
|
|
appId: mockAppId,
|
|
};
|
|
|
|
await handler(req, res);
|
|
|
|
expect(mockOnRequestStart).toHaveBeenCalledWith(
|
|
expect.anything(/* Assume original request */),
|
|
expect.objectContaining({
|
|
authToken: "mock-auth-token",
|
|
saleorDomain: "https://mock-saleor-domain.saleor.cloud/",
|
|
saleorApiUrl: "https://mock-saleor-domain.saleor.cloud/graphql/",
|
|
})
|
|
);
|
|
expect(mockOnRequestVerified).toHaveBeenCalledWith(
|
|
expect.anything(/* Assume original request */),
|
|
expect.objectContaining({
|
|
authData: expectedAuthData,
|
|
})
|
|
);
|
|
expect(mockOnAuthAplSaved).toHaveBeenCalledWith(
|
|
expect.anything(/* Assume original request */),
|
|
expect.objectContaining({
|
|
authData: expectedAuthData,
|
|
})
|
|
);
|
|
expect(mockOnAuthAplFailed).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("Runs callback hooks - failed saving to APL scenario", async () => {
|
|
const mockOnAuthAplFailed = vi.fn();
|
|
const mockOnAuthAplSaved = vi.fn();
|
|
|
|
(mockApl.set as Mock).mockImplementationOnce(() => {
|
|
throw new Error("test error");
|
|
});
|
|
|
|
const { res, req } = createMocks({
|
|
/**
|
|
* Use body, instead of params, otherwise - for some reason - param is not accessible in mock request
|
|
* Maybe this is a bug https://github.com/howardabrams/node-mocks-http/blob/master/lib/mockRequest.js
|
|
*/
|
|
body: {
|
|
auth_token: "mock-auth-token",
|
|
},
|
|
headers: {
|
|
host: "some-saleor-host.cloud",
|
|
"x-forwarded-proto": "https",
|
|
"saleor-api-url": "https://mock-saleor-domain.saleor.cloud/graphql/",
|
|
"saleor-domain": "https://mock-saleor-domain.saleor.cloud/",
|
|
},
|
|
method: "POST",
|
|
});
|
|
|
|
const handler = createAppRegisterHandler({
|
|
apl: mockApl,
|
|
onAplSetFailed: mockOnAuthAplFailed,
|
|
onAuthAplSaved: mockOnAuthAplSaved,
|
|
});
|
|
|
|
const expectedAuthData: AuthData = {
|
|
token: "mock-auth-token",
|
|
domain: "https://mock-saleor-domain.saleor.cloud/",
|
|
saleorApiUrl: "https://mock-saleor-domain.saleor.cloud/graphql/",
|
|
jwks: mockJwksValue,
|
|
appId: mockAppId,
|
|
};
|
|
|
|
await handler(req, res);
|
|
|
|
expect(mockOnAuthAplSaved).not.toHaveBeenCalled();
|
|
expect(mockOnAuthAplFailed).toHaveBeenCalledWith(
|
|
expect.anything(/* Assume original request */),
|
|
expect.objectContaining({
|
|
authData: expectedAuthData,
|
|
error: expect.objectContaining({
|
|
message: "test error",
|
|
}),
|
|
})
|
|
);
|
|
});
|
|
|
|
it("Allows to send custom error response via callback hook", async () => {
|
|
const mockOnRequestStart = vi.fn().mockImplementation(
|
|
(
|
|
req,
|
|
context: {
|
|
respondWithError(params: { status: number; body: string; message: string }): Error;
|
|
}
|
|
) =>
|
|
context.respondWithError({
|
|
status: 401,
|
|
body: "test",
|
|
message: "test message",
|
|
})
|
|
);
|
|
|
|
const { res, req } = createMocks({
|
|
/**
|
|
* Use body, instead of params, otherwise - for some reason - param is not accessible in mock request
|
|
* Maybe this is a bug https://github.com/howardabrams/node-mocks-http/blob/master/lib/mockRequest.js
|
|
*/
|
|
body: {
|
|
auth_token: "mock-auth-token",
|
|
},
|
|
headers: {
|
|
host: "some-saleor-host.cloud",
|
|
"x-forwarded-proto": "https",
|
|
"saleor-api-url": "https://mock-saleor-domain.saleor.cloud/graphql/",
|
|
"saleor-domain": "https://mock-saleor-domain.saleor.cloud/",
|
|
},
|
|
method: "POST",
|
|
});
|
|
|
|
const handler = createAppRegisterHandler({
|
|
apl: mockApl,
|
|
onRequestStart: mockOnRequestStart,
|
|
});
|
|
|
|
await handler(req, res);
|
|
|
|
expect(res._getStatusCode()).toBe(401);
|
|
expect(res._getData()).toEqual({
|
|
success: false,
|
|
error: {
|
|
code: "REGISTER_HANDLER_HOOK_ERROR",
|
|
message: "test message",
|
|
},
|
|
});
|
|
});
|
|
});
|
|
});
|