@tailor-platform/create-sdk 1.45.2 → 1.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/package.json +2 -2
- package/templates/executor/package.json +2 -2
- package/templates/executor/src/executor/onUserCreated.test.ts +30 -0
- package/templates/executor/src/executor/shared.test.ts +5 -21
- package/templates/executor/tailor.d.ts +1 -1
- package/templates/executor/vitest.config.ts +4 -0
- package/templates/generators/package.json +2 -2
- package/templates/generators/src/resolver/getProduct.test.ts +25 -49
- package/templates/generators/tailor.d.ts +1 -1
- package/templates/generators/vitest.config.ts +4 -0
- package/templates/hello-world/package.json +2 -2
- package/templates/hello-world/tailor.d.ts +1 -1
- package/templates/inventory-management/package.json +2 -2
- package/templates/inventory-management/tailor.d.ts +1 -1
- package/templates/multi-application/package.json +3 -3
- package/templates/resolver/README.md +1 -1
- package/templates/resolver/package.json +2 -4
- package/templates/resolver/src/resolver/incrementUserAge.test.ts +43 -0
- package/templates/resolver/tailor.d.ts +1 -1
- package/templates/resolver/vitest.config.ts +4 -6
- package/templates/static-web-site/package.json +2 -2
- package/templates/static-web-site/tailor.d.ts +1 -1
- package/templates/tailordb/package.json +2 -2
- package/templates/tailordb/tailor.d.ts +1 -1
- package/templates/tailordb/vitest.config.ts +4 -0
- package/templates/workflow/e2e/globalSetup.ts +2 -2
- package/templates/workflow/package.json +2 -4
- package/templates/workflow/src/resolver/resolveApproval.test.ts +15 -18
- package/templates/workflow/src/workflow/approval.test.ts +12 -18
- package/templates/workflow/tailor.d.ts +1 -1
- package/templates/workflow/vitest.config.ts +5 -6
- package/templates/resolver/src/resolver/queryUser.test.ts +0 -64
- package/templates/resolver/tests/bundled.test.ts +0 -98
- package/templates/workflow/tests/bundled.test.ts +0 -174
- /package/templates/resolver/src/resolver/{queryUser.ts → incrementUserAge.ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @tailor-platform/create-sdk
|
|
2
2
|
|
|
3
|
+
## 1.47.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#1115](https://github.com/tailor-platform/sdk/pull/1115) [`8dd619e`](https://github.com/tailor-platform/sdk/commit/8dd619e9c58f4662b117bbd968ecf9528d688fe4) Thanks [@toiroakr](https://github.com/toiroakr)! - Add `@tailor-platform/sdk/vitest` (beta) — a Vitest plugin and environment that emulates the Tailor Platform function runtime locally. Catches `node:*` imports and Node.js globals usage that would fail at deploy time, and provides mock control objects (`tailordbMock`, `workflowMock`, `secretmanagerMock`, `authconnectionMock`, `idpMock`, `fileMock`, `iconvMock`) for all platform APIs with response configuration and call recording.
|
|
8
|
+
|
|
9
|
+
Revamp `packages/sdk/docs/testing.md` into a 2-layer model (Unit Tests / E2E Tests). The previous structure split Unit, Bundled, and Workflow tests across overlapping sections and contained broken vitest imports and references to a non-existent `--template testing`. The new docs cover testing resolvers (simple, with TailorDB mocks, with DI, and with wait points) and workflow jobs (simple, with `triggerJobFunction` mocks, with wait-point mocks, and full-workflow integration), all anchored on the actual `resolver` and `workflow` templates.
|
|
10
|
+
|
|
11
|
+
Mark `createImportMain` and `setupInvokerMock` from `@tailor-platform/sdk/test` as `@deprecated`. `createImportMain` is an SDK-internal helper for verifying bundled output; applications should test their TypeScript source directly (unit) and verify deployed behavior via E2E. `setupInvokerMock` is superseded by the `tailor-runtime` Vitest environment, where bundled tests can drive the invoker via `vi.spyOn(globalThis.tailor.context, "getInvoker").mockReturnValue(...)` and unit tests can pass `invoker` directly to `.body()`. Both exports remain in place for now to avoid a breaking change and will be removed in a future release.
|
|
12
|
+
|
|
13
|
+
Remove the broken `tests/bundled.test.ts` from the `resolver` and `workflow` templates along with the related `bundled` vitest project and `test:bundled` / `test:bundled:prepare` scripts. These tests were not exercised by CI and had drifted out of sync with the SDK, producing failures on a fresh scaffold.
|
|
14
|
+
|
|
15
|
+
Fix a broken anchor in `docs/services/workflow.md` that pointed at the removed `#testing-wait-points` heading; it now links to `../testing.md#jobs-that-wait-on-approval` to match the new testing docs structure.
|
|
16
|
+
|
|
17
|
+
## 1.46.0
|
|
18
|
+
|
|
3
19
|
## 1.45.2
|
|
4
20
|
|
|
5
21
|
## 1.45.1
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tailor-platform/create-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.47.0",
|
|
4
4
|
"description": "A CLI tool to quickly create a new Tailor Platform SDK project",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
],
|
|
19
19
|
"type": "module",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@clack/prompts": "1.
|
|
21
|
+
"@clack/prompts": "1.3.0",
|
|
22
22
|
"execa": "9.6.1",
|
|
23
23
|
"picocolors": "1.1.1",
|
|
24
24
|
"pkg-types": "2.3.1",
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"generate": "tailor-sdk generate",
|
|
7
|
-
"deploy": "tailor-sdk
|
|
7
|
+
"deploy": "tailor-sdk deploy",
|
|
8
8
|
"test": "vitest --project unit",
|
|
9
9
|
"test:unit": "vitest --project unit",
|
|
10
10
|
"format": "oxfmt --write .",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@eslint/js": "10.0.1",
|
|
18
|
-
"@tailor-platform/sdk": "1.
|
|
18
|
+
"@tailor-platform/sdk": "1.47.0",
|
|
19
19
|
"@types/node": "24.12.2",
|
|
20
20
|
"eslint": "10.3.0",
|
|
21
21
|
"eslint-plugin-oxlint": "1.61.0",
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { describe, expect, test, vi } from "vitest";
|
|
2
|
+
import onUserCreated from "./onUserCreated";
|
|
3
|
+
import * as shared from "./shared";
|
|
4
|
+
|
|
5
|
+
describe("onUserCreated executor", () => {
|
|
6
|
+
test("creates an audit log with the new user's name and email", async () => {
|
|
7
|
+
const createAuditLog = vi.spyOn(shared, "createAuditLog").mockResolvedValue(undefined);
|
|
8
|
+
|
|
9
|
+
if (onUserCreated.operation.kind !== "function") {
|
|
10
|
+
throw new Error("expected function operation");
|
|
11
|
+
}
|
|
12
|
+
await onUserCreated.operation.body({
|
|
13
|
+
newRecord: {
|
|
14
|
+
id: "user-1",
|
|
15
|
+
name: "Alice",
|
|
16
|
+
email: "alice@example.com",
|
|
17
|
+
role: "ADMIN",
|
|
18
|
+
createdAt: "2025-01-01T00:00:00Z",
|
|
19
|
+
updatedAt: "2025-01-01T00:00:00Z",
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
expect(createAuditLog).toHaveBeenCalledExactlyOnceWith({
|
|
24
|
+
action: "USER_CREATED",
|
|
25
|
+
entityType: "User",
|
|
26
|
+
entityId: "user-1",
|
|
27
|
+
message: "Admin user created: Alice (alice@example.com)",
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -1,29 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { tailordbMock } from "@tailor-platform/sdk/vitest";
|
|
2
|
+
import { beforeEach, describe, expect, test } from "vitest";
|
|
2
3
|
import { createAuditLog } from "./shared";
|
|
3
4
|
|
|
4
5
|
describe("createAuditLog", () => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
vi.stubGlobal("tailordb", {
|
|
8
|
-
Client: vi.fn(
|
|
9
|
-
class {
|
|
10
|
-
connect = vi.fn();
|
|
11
|
-
end = vi.fn();
|
|
12
|
-
queryObject = mockQueryObject;
|
|
13
|
-
},
|
|
14
|
-
),
|
|
15
|
-
});
|
|
16
|
-
});
|
|
17
|
-
afterAll(() => {
|
|
18
|
-
vi.unstubAllGlobals();
|
|
19
|
-
});
|
|
20
|
-
afterEach(() => {
|
|
21
|
-
mockQueryObject.mockReset();
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
tailordbMock.reset();
|
|
22
8
|
});
|
|
23
9
|
|
|
24
10
|
test("inserts audit log record", async () => {
|
|
25
|
-
mockQueryObject.mockResolvedValueOnce({});
|
|
26
|
-
|
|
27
11
|
await createAuditLog({
|
|
28
12
|
action: "USER_CREATED",
|
|
29
13
|
entityType: "User",
|
|
@@ -31,6 +15,6 @@ describe("createAuditLog", () => {
|
|
|
31
15
|
message: "Test audit log",
|
|
32
16
|
});
|
|
33
17
|
|
|
34
|
-
expect(
|
|
18
|
+
expect(tailordbMock.executedQueries).toHaveLength(1);
|
|
35
19
|
});
|
|
36
20
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// This file is auto-generated by @tailor-platform/sdk
|
|
2
2
|
// Do not edit this file manually
|
|
3
|
-
// Regenerated automatically when running 'tailor-sdk
|
|
3
|
+
// Regenerated automatically when running 'tailor-sdk deploy' or 'tailor-sdk generate'
|
|
4
4
|
|
|
5
5
|
declare module "@tailor-platform/sdk" {
|
|
6
6
|
interface AttributeMap {
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { defineConfig } from "vitest/config";
|
|
2
|
+
import { tailorRuntime } from "@tailor-platform/sdk/vitest";
|
|
2
3
|
|
|
3
4
|
export default defineConfig({
|
|
5
|
+
plugins: [tailorRuntime()],
|
|
4
6
|
test: {
|
|
5
7
|
watch: false,
|
|
6
8
|
projects: [
|
|
7
9
|
{
|
|
10
|
+
extends: true,
|
|
8
11
|
test: {
|
|
9
12
|
name: { label: "unit", color: "blue" },
|
|
13
|
+
environment: "tailor-runtime",
|
|
10
14
|
include: ["src/**/*.test.ts"],
|
|
11
15
|
},
|
|
12
16
|
},
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"generate": "tailor-sdk generate",
|
|
7
|
-
"deploy": "tailor-sdk
|
|
7
|
+
"deploy": "tailor-sdk deploy",
|
|
8
8
|
"test": "vitest --project unit",
|
|
9
9
|
"test:unit": "vitest --project unit",
|
|
10
10
|
"format": "oxfmt --write .",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@eslint/js": "10.0.1",
|
|
18
|
-
"@tailor-platform/sdk": "1.
|
|
18
|
+
"@tailor-platform/sdk": "1.47.0",
|
|
19
19
|
"@types/node": "24.12.2",
|
|
20
20
|
"eslint": "10.3.0",
|
|
21
21
|
"eslint-plugin-oxlint": "1.61.0",
|
|
@@ -1,47 +1,27 @@
|
|
|
1
1
|
import { unauthenticatedTailorUser } from "@tailor-platform/sdk/test";
|
|
2
|
-
import {
|
|
2
|
+
import { tailordbMock } from "@tailor-platform/sdk/vitest";
|
|
3
|
+
import { beforeEach, describe, expect, test } from "vitest";
|
|
3
4
|
import resolver from "./getProduct";
|
|
4
5
|
|
|
5
6
|
describe("getProduct resolver", () => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
vi.stubGlobal("tailordb", {
|
|
9
|
-
Client: vi.fn(
|
|
10
|
-
class {
|
|
11
|
-
connect = vi.fn();
|
|
12
|
-
end = vi.fn();
|
|
13
|
-
queryObject = mockQueryObject;
|
|
14
|
-
},
|
|
15
|
-
),
|
|
16
|
-
});
|
|
17
|
-
});
|
|
18
|
-
afterAll(() => {
|
|
19
|
-
vi.unstubAllGlobals();
|
|
20
|
-
});
|
|
21
|
-
afterEach(() => {
|
|
22
|
-
mockQueryObject.mockReset();
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
tailordbMock.reset();
|
|
23
9
|
});
|
|
24
10
|
|
|
25
11
|
test("returns product with category", async () => {
|
|
26
12
|
// Select product
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
createdAt: new Date(),
|
|
37
|
-
updatedAt: null,
|
|
38
|
-
},
|
|
39
|
-
],
|
|
13
|
+
tailordbMock.enqueueResult({
|
|
14
|
+
id: "product-1",
|
|
15
|
+
name: "Widget",
|
|
16
|
+
price: 9.99,
|
|
17
|
+
status: "ACTIVE",
|
|
18
|
+
categoryId: "cat-1",
|
|
19
|
+
description: null,
|
|
20
|
+
createdAt: new Date(),
|
|
21
|
+
updatedAt: null,
|
|
40
22
|
});
|
|
41
23
|
// Select category
|
|
42
|
-
|
|
43
|
-
rows: [{ name: "Gadgets" }],
|
|
44
|
-
});
|
|
24
|
+
tailordbMock.enqueueResult({ name: "Gadgets" });
|
|
45
25
|
|
|
46
26
|
const result = await resolver.body({
|
|
47
27
|
input: { productId: "product-1" },
|
|
@@ -55,24 +35,20 @@ describe("getProduct resolver", () => {
|
|
|
55
35
|
status: "ACTIVE",
|
|
56
36
|
categoryName: "Gadgets",
|
|
57
37
|
});
|
|
58
|
-
expect(
|
|
38
|
+
expect(tailordbMock.executedQueries).toHaveLength(2);
|
|
59
39
|
});
|
|
60
40
|
|
|
61
41
|
test("returns product without category", async () => {
|
|
62
42
|
// Select product (no categoryId)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
createdAt: new Date(),
|
|
73
|
-
updatedAt: null,
|
|
74
|
-
},
|
|
75
|
-
],
|
|
43
|
+
tailordbMock.enqueueResult({
|
|
44
|
+
id: "product-2",
|
|
45
|
+
name: "Standalone Item",
|
|
46
|
+
price: 19.99,
|
|
47
|
+
status: "DRAFT",
|
|
48
|
+
categoryId: null,
|
|
49
|
+
description: null,
|
|
50
|
+
createdAt: new Date(),
|
|
51
|
+
updatedAt: null,
|
|
76
52
|
});
|
|
77
53
|
|
|
78
54
|
const result = await resolver.body({
|
|
@@ -87,6 +63,6 @@ describe("getProduct resolver", () => {
|
|
|
87
63
|
status: "DRAFT",
|
|
88
64
|
categoryName: null,
|
|
89
65
|
});
|
|
90
|
-
expect(
|
|
66
|
+
expect(tailordbMock.executedQueries).toHaveLength(1);
|
|
91
67
|
});
|
|
92
68
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// This file is auto-generated by @tailor-platform/sdk
|
|
2
2
|
// Do not edit this file manually
|
|
3
|
-
// Regenerated automatically when running 'tailor-sdk
|
|
3
|
+
// Regenerated automatically when running 'tailor-sdk deploy' or 'tailor-sdk generate'
|
|
4
4
|
|
|
5
5
|
declare module "@tailor-platform/sdk" {
|
|
6
6
|
interface AttributeMap {
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { defineConfig } from "vitest/config";
|
|
2
|
+
import { tailorRuntime } from "@tailor-platform/sdk/vitest";
|
|
2
3
|
|
|
3
4
|
export default defineConfig({
|
|
5
|
+
plugins: [tailorRuntime()],
|
|
4
6
|
test: {
|
|
5
7
|
watch: false,
|
|
6
8
|
projects: [
|
|
7
9
|
{
|
|
10
|
+
extends: true,
|
|
8
11
|
test: {
|
|
9
12
|
name: { label: "unit", color: "blue" },
|
|
13
|
+
environment: "tailor-runtime",
|
|
10
14
|
include: ["src/**/*.test.ts"],
|
|
11
15
|
},
|
|
12
16
|
},
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"private": true,
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"deploy": "tailor-sdk
|
|
6
|
+
"deploy": "tailor-sdk deploy",
|
|
7
7
|
"generate": "tailor-sdk generate",
|
|
8
8
|
"format": "oxfmt --write .",
|
|
9
9
|
"format:check": "oxfmt --check .",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@eslint/js": "10.0.1",
|
|
16
|
-
"@tailor-platform/sdk": "1.
|
|
16
|
+
"@tailor-platform/sdk": "1.47.0",
|
|
17
17
|
"@types/node": "24.12.2",
|
|
18
18
|
"eslint": "10.3.0",
|
|
19
19
|
"eslint-plugin-oxlint": "1.61.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// This file is auto-generated by @tailor-platform/sdk
|
|
2
2
|
// Do not edit this file manually
|
|
3
|
-
// Regenerated automatically when running 'tailor-sdk
|
|
3
|
+
// Regenerated automatically when running 'tailor-sdk deploy' or 'tailor-sdk generate'
|
|
4
4
|
|
|
5
5
|
declare module "@tailor-platform/sdk" {
|
|
6
6
|
interface AttributeMap {}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"private": true,
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"deploy": "tailor-sdk
|
|
6
|
+
"deploy": "tailor-sdk deploy",
|
|
7
7
|
"generate": "tailor-sdk generate",
|
|
8
8
|
"format": "oxfmt --write .",
|
|
9
9
|
"format:check": "oxfmt --check .",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@eslint/js": "10.0.1",
|
|
16
|
-
"@tailor-platform/sdk": "1.
|
|
16
|
+
"@tailor-platform/sdk": "1.47.0",
|
|
17
17
|
"@types/node": "24.12.2",
|
|
18
18
|
"eslint": "10.3.0",
|
|
19
19
|
"eslint-plugin-oxlint": "1.61.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// This file is auto-generated by @tailor-platform/sdk
|
|
2
2
|
// Do not edit this file manually
|
|
3
|
-
// Regenerated automatically when running 'tailor-sdk
|
|
3
|
+
// Regenerated automatically when running 'tailor-sdk deploy' or 'tailor-sdk generate'
|
|
4
4
|
|
|
5
5
|
declare module "@tailor-platform/sdk" {
|
|
6
6
|
interface AttributeMap {
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"deploy": "pnpm run deploy:user && pnpm run deploy:admin",
|
|
7
|
-
"deploy:user": "tailor-sdk
|
|
8
|
-
"deploy:admin": "tailor-sdk
|
|
7
|
+
"deploy:user": "tailor-sdk deploy -c apps/user/tailor.config.ts",
|
|
8
|
+
"deploy:admin": "tailor-sdk deploy -c apps/admin/tailor.config.ts",
|
|
9
9
|
"format": "oxfmt --write .",
|
|
10
10
|
"format:check": "oxfmt --check .",
|
|
11
11
|
"lint": "oxlint --type-aware . && eslint --cache .",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@eslint/js": "10.0.1",
|
|
17
|
-
"@tailor-platform/sdk": "1.
|
|
17
|
+
"@tailor-platform/sdk": "1.47.0",
|
|
18
18
|
"@types/node": "24.12.2",
|
|
19
19
|
"eslint": "10.3.0",
|
|
20
20
|
"eslint-plugin-oxlint": "1.61.0",
|
|
@@ -13,7 +13,7 @@ Demonstrates all resolver patterns with comprehensive testing approaches.
|
|
|
13
13
|
## Testing Approaches
|
|
14
14
|
|
|
15
15
|
1. **Direct `body()` call** - Simple resolvers with `unauthenticatedTailorUser`
|
|
16
|
-
2.
|
|
16
|
+
2. **`tailor-runtime` environment + `tailordbMock`** - Database resolvers via `tailordbMock` from `@tailor-platform/sdk/vitest` (no `vi.stubGlobal` needed)
|
|
17
17
|
3. **Dependency injection** - Extract `DbOperations` interface for testability
|
|
18
18
|
|
|
19
19
|
## Getting Started
|
|
@@ -4,11 +4,9 @@
|
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"generate": "tailor-sdk generate",
|
|
7
|
-
"deploy": "tailor-sdk
|
|
7
|
+
"deploy": "tailor-sdk deploy",
|
|
8
8
|
"test": "vitest --project unit",
|
|
9
9
|
"test:unit": "vitest --project unit",
|
|
10
|
-
"test:bundled:prepare": "TAILOR_PLATFORM_SDK_BUILD_ONLY=true tailor-sdk apply -c tailor.config.ts",
|
|
11
|
-
"test:bundled": "pnpm test:bundled:prepare && vitest --project bundled",
|
|
12
10
|
"format": "oxfmt --write .",
|
|
13
11
|
"format:check": "oxfmt --check .",
|
|
14
12
|
"lint": "oxlint --type-aware . && eslint --cache .",
|
|
@@ -17,7 +15,7 @@
|
|
|
17
15
|
},
|
|
18
16
|
"devDependencies": {
|
|
19
17
|
"@eslint/js": "10.0.1",
|
|
20
|
-
"@tailor-platform/sdk": "1.
|
|
18
|
+
"@tailor-platform/sdk": "1.47.0",
|
|
21
19
|
"@types/node": "24.12.2",
|
|
22
20
|
"eslint": "10.3.0",
|
|
23
21
|
"eslint-plugin-oxlint": "1.61.0",
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { unauthenticatedTailorUser } from "@tailor-platform/sdk/test";
|
|
2
|
+
import { tailordbMock } from "@tailor-platform/sdk/vitest";
|
|
3
|
+
import { beforeEach, describe, expect, test } from "vitest";
|
|
4
|
+
import resolver from "./incrementUserAge";
|
|
5
|
+
|
|
6
|
+
describe("incrementUserAge resolver", () => {
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
tailordbMock.reset();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test("increments user age", async () => {
|
|
12
|
+
tailordbMock.enqueueResults(
|
|
13
|
+
[], // BEGIN
|
|
14
|
+
[{ age: 30 }], // SELECT
|
|
15
|
+
[], // UPDATE
|
|
16
|
+
[], // COMMIT
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
const result = await resolver.body({
|
|
20
|
+
input: { email: "test@example.com" },
|
|
21
|
+
user: unauthenticatedTailorUser,
|
|
22
|
+
env: { appName: "Resolver Template", version: 1 },
|
|
23
|
+
});
|
|
24
|
+
expect(result).toEqual({ oldAge: 30, newAge: 31 });
|
|
25
|
+
expect(tailordbMock.executedQueries).toHaveLength(4);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("throws when user not found", async () => {
|
|
29
|
+
tailordbMock.enqueueResults(
|
|
30
|
+
[], // BEGIN
|
|
31
|
+
[], // SELECT (empty)
|
|
32
|
+
[], // ROLLBACK
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const result = resolver.body({
|
|
36
|
+
input: { email: "test@example.com" },
|
|
37
|
+
user: unauthenticatedTailorUser,
|
|
38
|
+
env: { appName: "Resolver Template", version: 1 },
|
|
39
|
+
});
|
|
40
|
+
await expect(result).rejects.toThrowError();
|
|
41
|
+
expect(tailordbMock.executedQueries).toHaveLength(3);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// This file is auto-generated by @tailor-platform/sdk
|
|
2
2
|
// Do not edit this file manually
|
|
3
|
-
// Regenerated automatically when running 'tailor-sdk
|
|
3
|
+
// Regenerated automatically when running 'tailor-sdk deploy' or 'tailor-sdk generate'
|
|
4
4
|
|
|
5
5
|
declare module "@tailor-platform/sdk" {
|
|
6
6
|
interface AttributeMap {
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
import { defineConfig } from "vitest/config";
|
|
2
|
+
import { tailorRuntime } from "@tailor-platform/sdk/vitest";
|
|
2
3
|
|
|
3
4
|
export default defineConfig({
|
|
5
|
+
plugins: [tailorRuntime()],
|
|
4
6
|
test: {
|
|
5
7
|
watch: false,
|
|
6
8
|
projects: [
|
|
7
9
|
{
|
|
10
|
+
extends: true,
|
|
8
11
|
test: {
|
|
9
12
|
name: { label: "unit", color: "blue" },
|
|
13
|
+
environment: "tailor-runtime",
|
|
10
14
|
include: ["src/**/*.test.ts"],
|
|
11
15
|
},
|
|
12
16
|
},
|
|
13
|
-
{
|
|
14
|
-
test: {
|
|
15
|
-
name: { label: "bundled", color: "yellow" },
|
|
16
|
-
include: ["tests/**/*.test.ts"],
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
17
|
],
|
|
20
18
|
},
|
|
21
19
|
});
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"private": true,
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"deploy": "tailor-sdk
|
|
6
|
+
"deploy": "tailor-sdk deploy",
|
|
7
7
|
"generate": "tailor-sdk generate",
|
|
8
8
|
"format": "oxfmt --write .",
|
|
9
9
|
"format:check": "oxfmt --check .",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@eslint/js": "10.0.1",
|
|
16
|
-
"@tailor-platform/sdk": "1.
|
|
16
|
+
"@tailor-platform/sdk": "1.47.0",
|
|
17
17
|
"@types/node": "24.12.2",
|
|
18
18
|
"eslint": "10.3.0",
|
|
19
19
|
"eslint-plugin-oxlint": "1.61.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// This file is auto-generated by @tailor-platform/sdk
|
|
2
2
|
// Do not edit this file manually
|
|
3
|
-
// Regenerated automatically when running 'tailor-sdk
|
|
3
|
+
// Regenerated automatically when running 'tailor-sdk deploy' or 'tailor-sdk generate'
|
|
4
4
|
|
|
5
5
|
declare module "@tailor-platform/sdk" {
|
|
6
6
|
interface AttributeMap {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"generate": "tailor-sdk generate",
|
|
7
|
-
"deploy": "tailor-sdk
|
|
7
|
+
"deploy": "tailor-sdk deploy",
|
|
8
8
|
"test": "vitest --project unit",
|
|
9
9
|
"test:unit": "vitest --project unit",
|
|
10
10
|
"format": "oxfmt --write .",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@eslint/js": "10.0.1",
|
|
18
|
-
"@tailor-platform/sdk": "1.
|
|
18
|
+
"@tailor-platform/sdk": "1.47.0",
|
|
19
19
|
"@types/node": "24.12.2",
|
|
20
20
|
"eslint": "10.3.0",
|
|
21
21
|
"eslint-plugin-oxlint": "1.61.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// This file is auto-generated by @tailor-platform/sdk
|
|
2
2
|
// Do not edit this file manually
|
|
3
|
-
// Regenerated automatically when running 'tailor-sdk
|
|
3
|
+
// Regenerated automatically when running 'tailor-sdk deploy' or 'tailor-sdk generate'
|
|
4
4
|
|
|
5
5
|
declare module "@tailor-platform/sdk" {
|
|
6
6
|
interface AttributeMap {
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { defineConfig } from "vitest/config";
|
|
2
|
+
import { tailorRuntime } from "@tailor-platform/sdk/vitest";
|
|
2
3
|
|
|
3
4
|
export default defineConfig({
|
|
5
|
+
plugins: [tailorRuntime()],
|
|
4
6
|
test: {
|
|
5
7
|
watch: false,
|
|
6
8
|
projects: [
|
|
7
9
|
{
|
|
10
|
+
extends: true,
|
|
8
11
|
test: {
|
|
9
12
|
name: { label: "unit", color: "blue" },
|
|
13
|
+
environment: "tailor-runtime",
|
|
10
14
|
include: ["src/**/*.test.ts"],
|
|
11
15
|
},
|
|
12
16
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
deploy,
|
|
3
3
|
getMachineUserToken,
|
|
4
4
|
show,
|
|
5
5
|
createWorkspace,
|
|
@@ -31,7 +31,7 @@ async function setupWorkspace(name: string, region: string): Promise<WorkspaceIn
|
|
|
31
31
|
|
|
32
32
|
async function deployApplication(): Promise<void> {
|
|
33
33
|
console.log("Deploying application...");
|
|
34
|
-
await
|
|
34
|
+
await deploy();
|
|
35
35
|
console.log("Application deployed successfully.");
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -4,11 +4,9 @@
|
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"generate": "tailor-sdk generate",
|
|
7
|
-
"deploy": "tailor-sdk
|
|
7
|
+
"deploy": "tailor-sdk deploy",
|
|
8
8
|
"test": "vitest --project unit",
|
|
9
9
|
"test:unit": "vitest --project unit",
|
|
10
|
-
"test:bundled:prepare": "TAILOR_PLATFORM_SDK_BUILD_ONLY=true tailor-sdk apply -c tailor.config.ts",
|
|
11
|
-
"test:bundled": "pnpm test:bundled:prepare && vitest --project bundled",
|
|
12
10
|
"test:e2e": "vitest --project e2e",
|
|
13
11
|
"format": "oxfmt --write .",
|
|
14
12
|
"format:check": "oxfmt --check .",
|
|
@@ -18,7 +16,7 @@
|
|
|
18
16
|
},
|
|
19
17
|
"devDependencies": {
|
|
20
18
|
"@eslint/js": "10.0.1",
|
|
21
|
-
"@tailor-platform/sdk": "1.
|
|
19
|
+
"@tailor-platform/sdk": "1.47.0",
|
|
22
20
|
"@types/node": "24.12.2",
|
|
23
21
|
"eslint": "10.3.0",
|
|
24
22
|
"eslint-plugin-oxlint": "1.61.0",
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { beforeEach, describe, expect, test } from "vitest";
|
|
2
|
+
import { workflowMock } from "@tailor-platform/sdk/vitest";
|
|
3
|
+
import { unauthenticatedTailorUser } from "@tailor-platform/sdk/test";
|
|
3
4
|
import resolver from "./resolveApproval";
|
|
4
5
|
|
|
5
|
-
const TailorGlobal = globalThis as { tailor?: { workflow?: Record<string, unknown> } };
|
|
6
|
-
|
|
7
6
|
describe("resolveApproval resolver", () => {
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
workflowMock.reset();
|
|
10
9
|
});
|
|
11
10
|
|
|
12
11
|
test("resolves approval with approved=true", async () => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
12
|
+
workflowMock.setResolveHandler((_executionId, _key, callback) => {
|
|
13
|
+
const callbackResult = callback({
|
|
14
|
+
message: "Please approve order order-1",
|
|
15
|
+
orderId: "order-1",
|
|
16
|
+
});
|
|
17
|
+
expect(callbackResult).toEqual({ approved: true });
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
const result = await resolver.body({
|
|
@@ -24,16 +24,13 @@ describe("resolveApproval resolver", () => {
|
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
expect(result).toEqual({ resolved: true });
|
|
27
|
-
expect(resolveCalls).
|
|
28
|
-
expect(resolveCalls[0]).toEqual({ executionId: "exec-1", key: "approval" });
|
|
27
|
+
expect(workflowMock.resolveCalls).toEqual([{ executionId: "exec-1", key: "approval" }]);
|
|
29
28
|
});
|
|
30
29
|
|
|
31
30
|
test("resolves approval with approved=false", async () => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
expect(result).toEqual({ approved: false });
|
|
36
|
-
},
|
|
31
|
+
workflowMock.setResolveHandler((_executionId, _key, callback) => {
|
|
32
|
+
const callbackResult = callback({ message: "Please approve", orderId: "order-2" });
|
|
33
|
+
expect(callbackResult).toEqual({ approved: false });
|
|
37
34
|
});
|
|
38
35
|
|
|
39
36
|
const result = await resolver.body({
|
|
@@ -1,34 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { beforeEach, describe, expect, test } from "vitest";
|
|
2
|
+
import { workflowMock } from "@tailor-platform/sdk/vitest";
|
|
3
3
|
import workflow, { processWithApproval } from "./approval";
|
|
4
4
|
|
|
5
|
-
const TailorGlobal = globalThis as { tailor?: { workflow?: Record<string, unknown> } };
|
|
6
|
-
|
|
7
5
|
describe("approval workflow", () => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
vi.restoreAllMocks();
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
workflowMock.reset();
|
|
11
8
|
});
|
|
12
9
|
|
|
13
10
|
test("approved flow returns approved status", async () => {
|
|
14
|
-
|
|
15
|
-
onWait: (_key, _payload) => ({ approved: true }),
|
|
16
|
-
});
|
|
11
|
+
workflowMock.setWaitHandler((_key, _payload) => ({ approved: true }));
|
|
17
12
|
|
|
18
13
|
const result = await processWithApproval.body({ orderId: "order-1" }, { env: {} });
|
|
19
14
|
|
|
20
15
|
expect(result).toEqual({ orderId: "order-1", status: "approved" });
|
|
21
|
-
expect(waitCalls).
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
expect(workflowMock.waitCalls).toEqual([
|
|
17
|
+
{
|
|
18
|
+
key: "approval",
|
|
19
|
+
payload: { message: "Please approve order order-1", orderId: "order-1" },
|
|
20
|
+
},
|
|
21
|
+
]);
|
|
26
22
|
});
|
|
27
23
|
|
|
28
24
|
test("rejected flow returns rejected status", async () => {
|
|
29
|
-
|
|
30
|
-
onWait: () => ({ approved: false }),
|
|
31
|
-
});
|
|
25
|
+
workflowMock.setWaitHandler({ approved: false });
|
|
32
26
|
|
|
33
27
|
const result = await processWithApproval.body({ orderId: "order-2" }, { env: {} });
|
|
34
28
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// This file is auto-generated by @tailor-platform/sdk
|
|
2
2
|
// Do not edit this file manually
|
|
3
|
-
// Regenerated automatically when running 'tailor-sdk
|
|
3
|
+
// Regenerated automatically when running 'tailor-sdk deploy' or 'tailor-sdk generate'
|
|
4
4
|
|
|
5
5
|
declare module "@tailor-platform/sdk" {
|
|
6
6
|
interface AttributeMap {
|
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
import { defineConfig } from "vitest/config";
|
|
2
|
+
import { tailorRuntime } from "@tailor-platform/sdk/vitest";
|
|
2
3
|
|
|
3
4
|
export default defineConfig({
|
|
5
|
+
plugins: [tailorRuntime()],
|
|
4
6
|
test: {
|
|
5
7
|
watch: false,
|
|
6
8
|
projects: [
|
|
7
9
|
{
|
|
10
|
+
extends: true,
|
|
8
11
|
test: {
|
|
9
12
|
name: { label: "unit", color: "blue" },
|
|
13
|
+
environment: "tailor-runtime",
|
|
10
14
|
include: ["src/**/*.test.ts"],
|
|
11
15
|
},
|
|
12
16
|
},
|
|
13
17
|
{
|
|
14
|
-
|
|
15
|
-
name: { label: "bundled", color: "yellow" },
|
|
16
|
-
include: ["tests/**/*.test.ts"],
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
{
|
|
18
|
+
extends: true,
|
|
20
19
|
test: {
|
|
21
20
|
name: { label: "e2e", color: "green" },
|
|
22
21
|
include: ["e2e/**/*.test.ts"],
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { unauthenticatedTailorUser } from "@tailor-platform/sdk/test";
|
|
2
|
-
import { afterAll, afterEach, beforeAll, describe, expect, test, vi } from "vitest";
|
|
3
|
-
import resolver from "./queryUser";
|
|
4
|
-
|
|
5
|
-
describe("incrementUserAge resolver", () => {
|
|
6
|
-
const mockQueryObject = vi.fn();
|
|
7
|
-
beforeAll(() => {
|
|
8
|
-
vi.stubGlobal("tailordb", {
|
|
9
|
-
Client: vi.fn(
|
|
10
|
-
class {
|
|
11
|
-
connect = vi.fn();
|
|
12
|
-
end = vi.fn();
|
|
13
|
-
queryObject = mockQueryObject;
|
|
14
|
-
},
|
|
15
|
-
),
|
|
16
|
-
});
|
|
17
|
-
});
|
|
18
|
-
afterAll(() => {
|
|
19
|
-
vi.unstubAllGlobals();
|
|
20
|
-
});
|
|
21
|
-
afterEach(() => {
|
|
22
|
-
mockQueryObject.mockReset();
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test("increments user age", async () => {
|
|
26
|
-
// 1: Begin transaction
|
|
27
|
-
mockQueryObject.mockResolvedValueOnce({});
|
|
28
|
-
// 2: Select current age
|
|
29
|
-
mockQueryObject.mockResolvedValueOnce({
|
|
30
|
-
rows: [{ age: 30 }],
|
|
31
|
-
});
|
|
32
|
-
// 3: Update age
|
|
33
|
-
mockQueryObject.mockResolvedValueOnce({});
|
|
34
|
-
// 4: Commit transaction
|
|
35
|
-
mockQueryObject.mockResolvedValueOnce({});
|
|
36
|
-
|
|
37
|
-
const result = await resolver.body({
|
|
38
|
-
input: { email: "test@example.com" },
|
|
39
|
-
user: unauthenticatedTailorUser,
|
|
40
|
-
env: { appName: "Resolver Template", version: 1 },
|
|
41
|
-
});
|
|
42
|
-
expect(result).toEqual({ oldAge: 30, newAge: 31 });
|
|
43
|
-
expect(mockQueryObject).toHaveBeenCalledTimes(4);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
test("throws when user not found", async () => {
|
|
47
|
-
// 1: Begin transaction
|
|
48
|
-
mockQueryObject.mockResolvedValueOnce({});
|
|
49
|
-
// 2: Select current age (no rows returned)
|
|
50
|
-
mockQueryObject.mockResolvedValueOnce({
|
|
51
|
-
rows: [],
|
|
52
|
-
});
|
|
53
|
-
// 3: Rollback transaction
|
|
54
|
-
mockQueryObject.mockResolvedValueOnce({});
|
|
55
|
-
|
|
56
|
-
const result = resolver.body({
|
|
57
|
-
input: { email: "test@example.com" },
|
|
58
|
-
user: unauthenticatedTailorUser,
|
|
59
|
-
env: { appName: "Resolver Template", version: 1 },
|
|
60
|
-
});
|
|
61
|
-
await expect(result).rejects.toThrowError();
|
|
62
|
-
expect(mockQueryObject).toHaveBeenCalledTimes(3);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { createImportMain, setupInvokerMock, setupTailordbMock } from "@tailor-platform/sdk/test";
|
|
3
|
-
import { beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
4
|
-
|
|
5
|
-
const outputDir = path.join(__dirname, "../.tailor-sdk");
|
|
6
|
-
|
|
7
|
-
describe("bundled resolver execution", () => {
|
|
8
|
-
let executedQueries: { query: string; params: unknown[] }[];
|
|
9
|
-
|
|
10
|
-
const importMain = createImportMain(outputDir);
|
|
11
|
-
|
|
12
|
-
beforeAll(() => {
|
|
13
|
-
({ executedQueries } = setupTailordbMock());
|
|
14
|
-
setupInvokerMock(null);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
executedQueries.length = 0;
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
describe("add resolver", () => {
|
|
22
|
-
test("returns sum of inputs", async () => {
|
|
23
|
-
const main = await importMain("resolvers/add.js");
|
|
24
|
-
const result = await main({ input: { left: 3, right: 4 } });
|
|
25
|
-
expect(result).toBe(7);
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
describe("incrementUserAge resolver", () => {
|
|
30
|
-
test("increments user age with DB mock", async () => {
|
|
31
|
-
setupTailordbMock((query) => {
|
|
32
|
-
if (query.includes("SELECT") || query.includes("select")) {
|
|
33
|
-
return [{ age: 30 }];
|
|
34
|
-
}
|
|
35
|
-
return [];
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
const main = await importMain("resolvers/incrementUserAge.js");
|
|
39
|
-
const result = await main({ input: { email: "test@example.com" } });
|
|
40
|
-
expect(result).toEqual({ oldAge: 30, newAge: 31 });
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe("decrementUserAge resolver", () => {
|
|
45
|
-
test("decrements user age with DB mock", async () => {
|
|
46
|
-
setupTailordbMock((query) => {
|
|
47
|
-
if (query.includes("SELECT") || query.includes("select")) {
|
|
48
|
-
return [
|
|
49
|
-
{
|
|
50
|
-
id: "user-1",
|
|
51
|
-
email: "test@example.com",
|
|
52
|
-
name: "Test",
|
|
53
|
-
age: 30,
|
|
54
|
-
createdAt: null,
|
|
55
|
-
updatedAt: null,
|
|
56
|
-
},
|
|
57
|
-
];
|
|
58
|
-
}
|
|
59
|
-
return [];
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
const main = await importMain("resolvers/decrementUserAge.js");
|
|
63
|
-
const result = await main({ input: { email: "test@example.com" } });
|
|
64
|
-
expect(result).toEqual({ oldAge: 30, newAge: 29 });
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
describe("showUserInfo resolver", () => {
|
|
69
|
-
test("returns user info from context", async () => {
|
|
70
|
-
const main = await importMain("resolvers/showUserInfo.js");
|
|
71
|
-
const result = await main({
|
|
72
|
-
user: {
|
|
73
|
-
id: "test-id",
|
|
74
|
-
type: "machine_user",
|
|
75
|
-
workspaceId: "ws-id",
|
|
76
|
-
attributes: { role: "admin" },
|
|
77
|
-
attributeList: [],
|
|
78
|
-
},
|
|
79
|
-
});
|
|
80
|
-
expect(result).toEqual({
|
|
81
|
-
userId: "test-id",
|
|
82
|
-
userType: "machine_user",
|
|
83
|
-
workspaceId: "ws-id",
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
describe("showEnv resolver", () => {
|
|
89
|
-
test("returns env values embedded from config", async () => {
|
|
90
|
-
const main = await importMain("resolvers/showEnv.js");
|
|
91
|
-
const result = await main({ env: { appName: "Resolver Template", version: 1 } });
|
|
92
|
-
expect(result).toEqual({
|
|
93
|
-
appName: "Resolver Template",
|
|
94
|
-
version: 1,
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
});
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import {
|
|
3
|
-
createImportMain,
|
|
4
|
-
setupInvokerMock,
|
|
5
|
-
setupTailordbMock,
|
|
6
|
-
setupWaitPointMock,
|
|
7
|
-
setupWorkflowMock,
|
|
8
|
-
} from "@tailor-platform/sdk/test";
|
|
9
|
-
import { beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
10
|
-
|
|
11
|
-
const outputDir = path.join(__dirname, "../.tailor-sdk");
|
|
12
|
-
|
|
13
|
-
describe("bundled workflow execution", () => {
|
|
14
|
-
let executedQueries: { query: string; params: unknown[] }[];
|
|
15
|
-
|
|
16
|
-
const importMain = createImportMain(outputDir);
|
|
17
|
-
|
|
18
|
-
beforeAll(() => {
|
|
19
|
-
({ executedQueries } = setupTailordbMock());
|
|
20
|
-
setupInvokerMock(null);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
beforeEach(() => {
|
|
24
|
-
executedQueries.length = 0;
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe("sync-profile job", () => {
|
|
28
|
-
test("creates new user when not found", async () => {
|
|
29
|
-
let selectCalled = false;
|
|
30
|
-
setupTailordbMock((query) => {
|
|
31
|
-
if (query.includes("SELECT") || query.includes("select")) {
|
|
32
|
-
if (!selectCalled) {
|
|
33
|
-
selectCalled = true;
|
|
34
|
-
return [];
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
if (query.includes("INSERT") || query.includes("insert")) {
|
|
38
|
-
return [
|
|
39
|
-
{
|
|
40
|
-
id: "new-id",
|
|
41
|
-
name: "Alice",
|
|
42
|
-
email: "alice@example.com",
|
|
43
|
-
age: 25,
|
|
44
|
-
createdAt: "2024-01-01",
|
|
45
|
-
updatedAt: null,
|
|
46
|
-
},
|
|
47
|
-
];
|
|
48
|
-
}
|
|
49
|
-
return [];
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const main = await importMain("workflow-jobs/sync-profile.js");
|
|
53
|
-
const result = await main({ name: "Alice", email: "alice@example.com", age: 25 });
|
|
54
|
-
expect(result).toEqual({
|
|
55
|
-
created: true,
|
|
56
|
-
profile: { name: "Alice", email: "alice@example.com", age: 25 },
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
test("updates existing user when found", async () => {
|
|
61
|
-
setupTailordbMock((query) => {
|
|
62
|
-
if (query.includes("SELECT") || query.includes("select")) {
|
|
63
|
-
return [
|
|
64
|
-
{
|
|
65
|
-
id: "existing-id",
|
|
66
|
-
name: "Old Name",
|
|
67
|
-
email: "alice@example.com",
|
|
68
|
-
age: 20,
|
|
69
|
-
createdAt: "2024-01-01",
|
|
70
|
-
updatedAt: null,
|
|
71
|
-
},
|
|
72
|
-
];
|
|
73
|
-
}
|
|
74
|
-
return [];
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
const main = await importMain("workflow-jobs/sync-profile.js");
|
|
78
|
-
const result = await main({ name: "Alice Updated", email: "alice@example.com", age: 26 });
|
|
79
|
-
expect(result).toEqual({
|
|
80
|
-
created: false,
|
|
81
|
-
profile: { name: "Alice Updated", email: "alice@example.com", age: 26 },
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
describe("approval workflow job", () => {
|
|
87
|
-
test("process-with-approval returns approved when resolved with true", async () => {
|
|
88
|
-
setupWaitPointMock({
|
|
89
|
-
onWait: (_key, _payload) => ({ approved: true }),
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
const main = await importMain("workflow-jobs/process-with-approval.js");
|
|
93
|
-
const result = await main({ orderId: "order-1" });
|
|
94
|
-
expect(result).toEqual({ orderId: "order-1", status: "approved" });
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test("process-with-approval returns rejected when resolved with false", async () => {
|
|
98
|
-
setupWaitPointMock({
|
|
99
|
-
onWait: (_key, _payload) => ({ approved: false }),
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
const main = await importMain("workflow-jobs/process-with-approval.js");
|
|
103
|
-
const result = await main({ orderId: "order-2" });
|
|
104
|
-
expect(result).toEqual({ orderId: "order-2", status: "rejected" });
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
describe("order-fulfillment jobs", () => {
|
|
109
|
-
test("validate-order validates positive amount", async () => {
|
|
110
|
-
const main = await importMain("workflow-jobs/validate-order.js");
|
|
111
|
-
const result = await main({ orderId: "order-1", amount: 100 });
|
|
112
|
-
expect(result).toEqual({ valid: true, orderId: "order-1" });
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test("validate-order throws for non-positive amount", async () => {
|
|
116
|
-
const main = await importMain("workflow-jobs/validate-order.js");
|
|
117
|
-
await expect(main({ orderId: "order-1", amount: 0 })).rejects.toThrow(
|
|
118
|
-
"Order amount must be positive",
|
|
119
|
-
);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
test("process-payment returns transaction", async () => {
|
|
123
|
-
const main = await importMain("workflow-jobs/process-payment.js");
|
|
124
|
-
const result = await main({ orderId: "order-1", amount: 100 });
|
|
125
|
-
expect(result).toEqual({
|
|
126
|
-
transactionId: "txn-order-1",
|
|
127
|
-
amount: 100,
|
|
128
|
-
status: "completed",
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
test("send-confirmation returns confirmation", async () => {
|
|
133
|
-
const main = await importMain("workflow-jobs/send-confirmation.js");
|
|
134
|
-
const result = await main({ orderId: "order-1", transactionId: "txn-order-1" });
|
|
135
|
-
expect(result).toEqual({
|
|
136
|
-
orderId: "order-1",
|
|
137
|
-
transactionId: "txn-order-1",
|
|
138
|
-
confirmed: true,
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
test("fulfill-order orchestrates all jobs", async () => {
|
|
143
|
-
setupWorkflowMock((jobName, args) => {
|
|
144
|
-
switch (jobName) {
|
|
145
|
-
case "validate-order":
|
|
146
|
-
return { valid: true, orderId: (args as { orderId: string }).orderId };
|
|
147
|
-
case "process-payment":
|
|
148
|
-
return {
|
|
149
|
-
transactionId: `txn-${(args as { orderId: string }).orderId}`,
|
|
150
|
-
amount: (args as { amount: number }).amount,
|
|
151
|
-
status: "completed",
|
|
152
|
-
};
|
|
153
|
-
case "send-confirmation":
|
|
154
|
-
return {
|
|
155
|
-
orderId: (args as { orderId: string }).orderId,
|
|
156
|
-
transactionId: (args as { transactionId: string }).transactionId,
|
|
157
|
-
confirmed: true,
|
|
158
|
-
};
|
|
159
|
-
default:
|
|
160
|
-
throw new Error(`Unknown job: ${jobName}`);
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
const main = await importMain("workflow-jobs/fulfill-order.js");
|
|
165
|
-
const result = await main({ orderId: "order-1", amount: 100 });
|
|
166
|
-
expect(result).toEqual({
|
|
167
|
-
orderId: "order-1",
|
|
168
|
-
transactionId: "txn-order-1",
|
|
169
|
-
confirmed: true,
|
|
170
|
-
paymentStatus: "completed",
|
|
171
|
-
});
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
});
|
|
File without changes
|